programing tip

이동하는 생성자

itbloger 2020. 6. 14. 11:02
반응형

이동하는 생성자


구조체가 있고 합리적인 기본값으로 초기화하고 싶습니다.

일반적으로 여기에서해야 할 일은 생성자를 사용하는 것이지만 go는 전통적인 의미에서 실제로 OOP가 아니기 때문에 실제 객체가 아니며 생성자가 없습니다.

init 메소드를 보았지만 패키지 레벨에 있습니다. 구조체 수준에서 사용할 수있는 다른 것이 있습니까?

그렇지 않은 경우 Go에서 이러한 유형의 작업에 허용되는 모범 사례는 무엇입니까?


실제로 두 가지 모범 사례가 허용됩니다.

  1. 구조체의 0 값을 적절한 기본값으로 설정하십시오. (이것은 "전통적인"oop에서 오는 대부분의 사람들에게는 이상하게 보이지만 종종 작동하고 실제로 편리합니다.)
  2. 기능을 제공 func New() YourTyp하거나 패키지 기능 등에 이러한 유형이 여러 개있는 경우 func NewYourType1() YourType1.

유형의 0 값을 사용할 수 있는지 여부를 문서화하십시오 (이 경우 New...기능 중 하나를 사용하여 설정해야 합니다). "전통 주의자"죄송합니다. 정의되지 않은 상태에서 객체를 만들 수없는 경우에도 유형을 올바르게 입력하십시오.)


0 값이 합리적인 기본값을 만들 수 없거나 구조체 초기화에 일부 매개 변수가 필요한 경우에 대한 생성자와 동등한 항목이 있습니다.

다음과 같은 구조체가 있다고 가정하십시오.

type Thing struct {
    Name  string
    Num   int
}

그런 다음 0 값이 맞지 않으면 일반적으로 NewThing포인터를 반환하는 함수로 인스턴스를 구성합니다 .

func NewThing(someParameter string) *Thing {
    p := new(Thing)
    p.Name = someParameter
    p.Num = 33 // <- a very sensible default value
    return p
}

구조체가 충분히 단순하면 다음 압축 구조를 사용할 수 있습니다.

func NewThing(someParameter string) *Thing {
    return &Thing{someParameter, 33}
}

포인터를 반환하지 않으려면 다음 makeThing대신 함수를 호출하는 것이 좋습니다 NewThing.

func makeThing(name string) Thing {
    return Thing{name, 33}
}

참조 : Effective Go의 새로운 기능으로 할당 .


바둑에는 물건이 있습니다. 객체에는 생성자가있을 수 있습니다 (자동 생성자는 아니지만). 마지막으로 Go는 OOP 언어입니다 (데이터 유형에는 메서드가 첨부되어 있지만 OOP의 정의는 끝이 없습니다.)

그럼에도 불구하고 허용되는 모범 사례는 유형에 대해 0 개 이상의 생성자를 작성하는 것입니다.

이 답변을 마치기 전에 @dystroy가 자신의 답변을 게시 했으므로 대신 예제 생성자의 대체 버전을 추가하겠습니다.

func NewThing(someParameter string) *Thing {
    return &Thing{someParameter, 33} // <- 33: a very sensible default value
}

이 버전을 보여 드리려는 이유는 "생성자"호출 대신 "인라인"리터럴을 사용할 수 있기 때문입니다.

a := NewThing("foo")
b := &Thing{"foo", 33}

이제 *a == *b.


Go에는 기본 생성자가 없지만 모든 유형의 메소드를 선언 할 수 있습니다. "Init"이라는 메소드를 선언하는 습관을 들일 수 있습니다. 이것이 모범 사례와 어떤 관련이 있는지 확실하지 않지만 명확성을 잃지 않고 이름을 짧게 유지하는 데 도움이됩니다.

package main

import "fmt"

type Thing struct {
    Name string
    Num int
}

func (t *Thing) Init(name string, num int) {
    t.Name = name
    t.Num = num
}

func main() {
    t := new(Thing)
    t.Init("Hello", 5)
    fmt.Printf("%s: %d\n", t.Name, t.Num)
}

결과는 다음과 같습니다.

Hello: 5

블로그 게시물 의 설명이 마음에 듭니다 .

New 함수는 애플리케이션 개발자가 사용할 핵심 유형 또는 다른 유형을 작성하는 패키지에 대한 Go 규칙입니다. log.go, bufio.go 및 cypto.go에서 New가 어떻게 정의되고 구현되는지 살펴보십시오 :

log.go

// New creates a new Logger. The out variable sets the
// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
func New(out io.Writer, prefix string, flag int) * Logger {
    return &Logger{out: out, prefix: prefix, flag: flag}
}

bufio.go

// NewReader returns a new Reader whose buffer has the default size.
func NewReader(rd io.Reader) * Reader {
    return NewReaderSize(rd, defaultBufSize)
}

crypto.go

// New returns a new hash.Hash calculating the given hash function. New panics
// if the hash function is not linked into the binary.
func (h Hash) New() hash.Hash {
    if h > 0 && h < maxHash {
        f := hashes[h]
        if f != nil {
            return f()
        }
    }
    panic("crypto: requested hash function is unavailable")
}

각 패키지는 네임 스페이스 역할을하기 때문에 모든 패키지는 고유 한 버전의 New를 가질 수 있습니다. bufio.go에서는 여러 유형을 만들 수 있으므로 독립형 새 기능이 없습니다. 여기에는 NewReader 및 NewWriter와 같은 기능이 있습니다.


다른 방법은;

package person

type Person struct {
    Name string
    Old  int
}

func New(name string, old int) *Person {
    // set only specific field value with field key
    return &Person{
        Name: name,
    }
}

If you want to force the factory function usage, name your struct (your class) with the first character in lowercase. Then, it won't be possible to instantiate directly the struct, the factory method will be required.

This visibility based on first character lower/upper case work also for struct field and for the function/method. If you don't want to allow external access, use lower case.


Golang is not OOP language in its official documents. All fields of Golang struct has a determined value(not like c/c++), so constructor function is not so necessary as cpp. If you need assign some fields some special values, use factory functions. Golang's community suggest New.. pattern names.


If you want to emulate ___.new() syntax you can do something along the lines of:

type Thing struct {
    Name string
    Num int
}
type Constructor_Thing struct {}
func (c CThing) new(<<CONSTRUCTOR ARGS>>) Thing {
  var thing Thing
  //initiate thing from constructor args
  return thing
}
var cThing CThing

func main(){
  var myThing Thing
  myThing = cThing.new(<<CONSTRUCTOR ARGS>>)
  //...
}

Granted, it is a shame that Thing.new() cannot be implemented without CThing.new() also being implemented (iirc) which is a bit of a shame...

참고URL : https://stackoverflow.com/questions/18125625/constructors-in-go

반응형