왜 내가 () 또는 new ()를 만들 것입니까?


203

도입 문서 사이의 차이를 설명하는 많은 단락을 할애 new()하고 make()있지만, 실제로는, 당신은 지역의 범위 내에서 객체를 생성하고 반환 할 수 있습니다.

할당 자 쌍을 왜 사용 하시겠습니까?

답변:


170

당신이 할 수있는 일 make이 다른 방법으로 할 수 없어 :

  • 채널 만들기
  • 공간이 미리 할당 된 맵 만들기
  • 공간이 미리 할당되거나 len! = cap로 슬라이스를 만듭니다.

정당화하기가 조금 더 어렵습니다 new. 가장 쉬운 것은 비 복합 유형에 대한 포인터를 만드는 것입니다. 아래의 두 기능은 동일합니다. 하나는 조금 더 간결합니다.

func newInt1() *int { return new(int) }

func newInt2() *int {
    var i int
    return &i
}

41
'신규'를 사용하여 채널을 만들 수는 없습니다. 그러나 내 의견으로는 요점은 'new'와 'make'가 단일 내장 함수에 결합되면 어떻게 될까요? 확실히 그러한 교체가 가능할 것입니다. 가능하기 때문에 문제는 다음과 같습니다. 하나의 일반화 된 내장 함수가 아닌 2 개의 내장 함수를 갖는 객관적인 이유는 무엇입니까? -정답은 'new'를 사용하여 채널 / 맵 / 슬라이스를 만들 수는 없지만 Go가 'new'와 'make'를 일반화 한 alloc + init 기능 대신 왜 사용했는지에 대한 근거는 제공하지 않습니다 .

5
그것들은 결합 될 수 있으며 Rob Pike가 groups.google.com/d/topic/golang-nuts/kWXYU95XN04/discussion 에서 제안했습니다 . 궁극적으로 그것은 당신의 대답에 주어진 것과 비슷한 이유로 통과하지 않았습니다.
Evan Shaw

12
효과적인 이동은 new가 0 값을 반환하는 반면 map은 0이 아닌 유형의 맵, 슬라이스 또는 채널을 할당합니다. 참조 golang.org/doc/effective_go.html#allocation_new
kristianp

무엇에 대해 m := map[string]int{}대신 m := make(map[string]int)? 크기를 미리 할당 할 필요가 없습니다.
Noam Manos

165

Go에는 여러 가지 메모리 할당 및 값 초기화 방법이 있습니다.

&T{...}, &someLocalVar, new,make

복합 리터럴을 만들 때 할당이 발생할 수도 있습니다.


new정수와 같은 값을 할당하는 데 사용할 수 있습니다 &int.

new(Point)
&Point{}      // OK
&Point{2, 3}  // Combines allocation and initialization

new(int)
&int          // Illegal

// Works, but it is less convenient to write than new(int)
var i int
&i

의 차이 new와는 make다음의 예를 보면 알 수있다 :

p := new(chan int)   // p has type: *chan int
c := make(chan int)  // c has type: chan int

Go에 newand make가 없지만 내장 기능 이 있다고 가정합니다 NEW. 그런 다음 예제 코드는 다음과 같습니다.

p := NEW(*chan int)  // * is mandatory
c := NEW(chan int)

* 필수가 될 것입니다 그래서 :

new(int)        -->  NEW(*int)
new(Point)      -->  NEW(*Point)
new(chan int)   -->  NEW(*chan int)
make([]int, 10) -->  NEW([]int, 10)

new(Point)  // Illegal
new(int)    // Illegal

예, 단일 내장 기능으로 병합 new및 통합 make할 수 있습니다. 그러나 단일 내장 기능이 내장 된 두 기능을 갖는 것보다 새로운 Go 프로그래머에게 더 많은 혼란을 야기 할 가능성이 있습니다.

위의 모든 사항을 고려하면 더 적절 new하고 make분리 된 상태로 유지됩니다.


@TorstenBronger 읽기 쉬운 새로운 것을 발견하고 그것이 int생성 된 인스턴스임을 보여줍니다 .
Daniel Toebe

4
당신은 쓰기에 의미했다 make(Point)make(int)그 마지막 두 줄?
Jimmy Huch

27

make함수는 slice, map 또는 chan 유형의 객체 만 할당하고 초기화합니다. 처럼 new첫 번째 인수는 유형입니다. 그러나 크기에 대한 두 번째 주장이 필요할 수도 있습니다. new와 달리 make의 반환 유형은 포인터의 유형이 아니라 인수의 유형과 동일합니다. 그리고 할당 된 값이 초기화됩니다 (새로운 것과 같이 0으로 설정되지 않음). 그 이유는 slice, map 및 chan이 데이터 구조이기 때문입니다. 초기화해야합니다. 그렇지 않으면 사용할 수 없습니다. 이것이 new ()와 make ()가 달라야하는 이유입니다.

Effective Go의 다음 예는 매우 명확합니다.

p *[]int = new([]int) // *p = nil, which makes p useless
v []int = make([]int, 100) // creates v structure that has pointer to an array, length field, and capacity field. So, v is immediately usable

1
에서 new([]int), 그것은 단지 [] int에 대한 메모리를 할당하지만 초기화하지 않기 때문에 단지 반환 nil한다; 사용할 수 없기 때문에 메모리에 대한 포인터가 아닙니다. make([]int)사용할 수 있도록 할당하고 초기화 한 다음 주소를 반환하십시오.
o0omycomputero0o

12
  • new(T)- 메모리를 할당하고, 집합에 그것은 제로 값 유형에 대한 T ..
    이다 ..that 0대해 INT , ""위한 문자열nil참조 타입 (위한 슬라이스 , 지도 , )

    참조 유형은 일부 단지 포인터 참고 것을 기본 데이터 구조 , 생성되지 않습니다 에 의해 new(T)
    의 경우 : 예 슬라이스 , 기본 배열이 생성되지 않습니다 따라서, new([]int) 아무것도 포인터를 반환

  • make(T)-참조 된 데이터 유형 ( slice , map , chan )에 메모리를 할당 하고 기본 데이터 구조를 초기화 합니다.

    예 : slice의 경우 지정된 길이와 용량으로 기본 배열 이 생성됩니다.
    C와 달리 배열은 Go!의 기본 유형입니다.


그 말은 :

  • make(T) 복합 리터럴 구문처럼 동작
  • new(T)처럼 행동한다 var(변수가 초기화되지 않은 경우)

    func main() {
        fmt.Println("-- MAKE --")
        a := make([]int, 0)
        aPtr := &a
        fmt.Println("pointer == nil :", *aPtr == nil)
        fmt.Printf("pointer value: %p\n\n", *aPtr)
    
        fmt.Println("-- COMPOSITE LITERAL --")
        b := []int{}
        bPtr := &b
        fmt.Println("pointer == nil :", *bPtr == nil)
        fmt.Printf("pointer value: %p\n\n", *bPtr)
    
        fmt.Println("-- NEW --")
        cPtr := new([]int)
        fmt.Println("pointer == nil :", *cPtr == nil)
        fmt.Printf("pointer value: %p\n\n", *cPtr)
    
        fmt.Println("-- VAR (not initialized) --")
        var d []int
        dPtr := &d
        fmt.Println("pointer == nil :", *dPtr == nil)
        fmt.Printf("pointer value: %p\n", *dPtr)
    }

    프로그램을 실행

    -- MAKE --
    pointer == nil : false
    pointer value: 0x118eff0  # address to underlying array
    
    -- COMPOSITE LITERAL --
    pointer == nil : false
    pointer value: 0x118eff0  # address to underlying array
    
    -- NEW --
    pointer == nil : true
    pointer value: 0x0
    
    -- VAR (not initialized) --
    pointer == nil : true
    pointer value: 0x0

    추가 읽기 :
    https://golang.org/doc/effective_go.html#allocation_new https://golang.org/doc/effective_go.html#allocation_make


  • 예를 들어 상황이 더 명확 해집니다. upvoted :)
    Suha Jha

    8

    당신은 필요한 make()채널과지도를 만들기 위해 (그리고 조각을, 그러나 그 너무 배열을 만들 수 있습니다). 대체 할 방법이 없으므로 make()사전에서 제거 할 수 없습니다 .

    에 관해서는 new(), 나는 어떤 이유를 모르는 즉석 당신이 왜 필요 를 당신은 구조체 구문을 사용할 수 있습니다 때. 그래도 고유 한 의미 론적 의미를 갖습니다. "모든 필드가 0으로 초기화 된 구조체를 생성하여 반환합니다"는 유용합니다.


    1
    따라서 새로운 것을 피하고 Struct 구문 사용을 선호하십시오
    CommonSenseCode

    8

    외에도 모든에서이 설명 효과적인 이동 , 주요 차이점을 사이 new(T)&T{} 후자는 명시 적으로 힙 할당을 수행하는 것입니다. 그러나 이는 구현에 따라 다르므로 변경 될 수 있습니다.

    비교 make하려면 new두 개의 완전히 다른 기능을 수행 할 때 약간의 의미가 있습니다. 그러나 이것은 링크 된 기사에서 자세히 설명됩니다.


    10
    &T{}명시 적으로 힙 할당을 수행 한다는 주장 은 사양의 내용을 기반으로하지 않는 AFAIK입니다. 실제로 나는 탈출 분석이와 같은 방식으로 가능한 한 항상 * T를 스택에 유지한다고 생각 new(T)합니다.
    zzzz

    6

    new (T) : 유형 T에 대한 포인터를 * T 유형의 값으로 리턴 하고 메모리를 할당하고 0으로 만듭니다. new (T)는 & T {}와 같습니다 .

    make (T) : T 타입초기화 된 값을 반환하고 , 메모리를 할당하고 초기화합니다. 슬라이스, 맵 및 채널에 사용됩니다.

    당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
    Licensed under cc by-sa 3.0 with attribution required.