[pointers] Go에서 리터럴 * int64를 어떻게 수행합니까?

*int64필드 가있는 구조체 유형이 있습니다.

type SomeType struct {
    SomeField *int64
}

내 코드의 어느 시점에서 나는 이것의 리터럴을 선언하고 싶습니다.

instance := SomeType{
    SomeField: &0,
}

… 이것은 작동하지 않는 것을 제외하고

./main.go:xx: cannot use &0 (type *int) as type *int64 in field value

그래서 나는 이것을 시도

instance := SomeType{
    SomeField: &int64(0),
}

…하지만 이것도 작동하지 않습니다

./main.go:xx: cannot take the address of int64(0)

어떻게해야합니까? 내가 생각 해낼 수있는 유일한 해결책은 자리 표시 자 변수를 사용하는 것입니다.

var placeholder int64
placeholder = 0

instance := SomeType{
    SomeField: &placeholder,
}

참고 : &0구문이 작동 벌금을 그것이 * INT는 대신 때 *int64. 편집 : 아니요. 이렇게되어 미안합니다.

편집하다:

분명히 내 질문에 너무 모호한 부분이있었습니다. 내가 할 수있는 방법을 찾고 있어요 그대로 상태*int64 . 이것은 생성자 내부에서 사용하거나 리터럴 구조체 값을 지정하거나 다른 함수에 대한 인수로 사용할 수도 있습니다. 그러나 도우미 기능이나 다른 유형을 사용하는 것은 내가 찾고있는 솔루션이 아닙니다.



답변

Go 언어 사양 ( 주소 연산자 )은 숫자 상수의 주소를 허용하지 않습니다 ( 유형이 지정되지 않았거나 입력 된 상수가 아님).

피연산자는 주소 지정가능 해야합니다 . 즉, 변수, 포인터 간접 지정 또는 슬라이스 인덱싱 작업 중 하나 여야합니다 . 또는 주소 지정 가능한 구조체 피연산자의 필드 선택자; 또는 주소 지정 가능한 배열의 배열 인덱싱 작업입니다. 주소 지정 요구 사항에 대한 예외로, x[의 표현에서 &x]는 복합 리터럴 일 수도 있습니다 (괄호 안에 있음) .

이것이 허용되지 않는 이유에 대해서는 관련 질문 : Find address of constant in go를 참조하십시오 . 유사한 질문 (비슷하게 주소를 사용할 수 없음) : Go에서 작업 결과에 대한 참조를 어떻게 저장할 수 있습니까?

옵션 ( Go Playground 에서 모두 시도 ) :

1) 함께 new()

내장 new()함수를 사용하여 새로운 0 값을 할당 int64하고 주소를 얻을 수 있습니다.

instance := SomeType{
    SomeField: new(int64),
}

그러나 이것은 모든 유형의 0 값에 대한 포인터를 할당하고 얻는 데만 사용할 수 있습니다.

2) 도우미 변수 사용

0이 아닌 요소에 대해 가장 간단하고 권장되는 것은 주소를 가져올 수있는 도우미 변수를 사용하는 것입니다.

helper := int64(2)
instance2 := SomeType{
    SomeField: &helper,
}

3) 도우미 기능 포함

참고 : 0이 아닌 값에 대한 포인터를 가져 오는 도우미 함수는 내 github.com/icza/gox라이브러리의 gox패키지 에서 사용할 수 있으므로 필요한 모든 프로젝트에 추가 할 필요가 없습니다.

또는 이것을 여러 번 필요로하는 경우 다음을 할당하고 반환하는 도우미 함수를 만들 수 있습니다 *int64.

func create(x int64) *int64 {
    return &x
}

그리고 그것을 사용 :

instance3 := SomeType{
    SomeField: create(3),
}

실제로 아무것도 할당하지 않았으며 Go 컴파일러는 함수 인수의 주소를 반환 할 때 할당했습니다. Go 컴파일러는 이스케이프 분석을 수행하고 함수를 이스케이프 할 수있는 경우 스택 대신 힙에 지역 변수를 할당합니다. 자세한 내용 은 Go 함수에서 로컬 배열 조각을 안전하게 반환합니까?를 참조하십시오.

4) 한 줄 익명 기능 사용

instance4 := SomeType{
    SomeField: func() *int64 { i := int64(4); return &i }(),
}

또는 (짧은) 대안으로 :

instance4 := SomeType{
    SomeField: func(i int64) *int64 { return &i }(4),
}

5) 슬라이스 리터럴, 인덱싱 및 주소 가져 오기

*SomeField이외의 사람 이되고 싶다면 0주소 지정이 가능한 것이 필요합니다.

여전히 그렇게 할 수 있지만 그것은 추합니다.

instance5 := SomeType{
    SomeField: &[]int64{5}[0],
}
fmt.Println(*instance2.SomeField) // Prints 5

여기서 일어나는 일은 []int64하나의 요소 ( 5)를 갖는 리터럴 로 슬라이스가 생성된다는 것 입니다. 그리고 색인화 (0 번째 요소)되고 0 번째 요소의 주소가 사용됩니다. 백그라운드에서의 배열 [1]int64도 할당되고 슬라이스의 지원 배열로 사용됩니다. 여기에는 많은 상용구가 있습니다.

6) 도우미 구조체 리터럴 사용

주소 지정 요구 사항에 대한 예외를 살펴 보겠습니다.

주소 지정 요구 사항에 대한 예외로, x[의 표현에서 &x]는 복합 리터럴 일 수도 있습니다 (괄호 안에 있음) .

이것은 합성 리터럴 (예 : 구조체 리터럴)의 주소를 취하는 것이 괜찮다는 것을 의미합니다. 그렇게하면 구조체 값이 할당되고 포인터가 획득됩니다. 그러나 그렇다면 “주소 지정 가능한 구조체 피연산자의 필드 선택자”라는 또 다른 요구 사항을 사용할 수 있습니다 . 따라서 구조체 리터럴에 유형의 필드가 포함되어 있으면 해당 필드의 int64주소를 가져올 수도 있습니다!

이 옵션이 실제로 작동하는지 살펴 보겠습니다. 이 래퍼 구조체 유형을 사용합니다.

type intwrapper struct {
    x int64
}

이제 다음을 수행 할 수 있습니다.

instance6 := SomeType{
    SomeField: &(&intwrapper{6}).x,
}

&(&intwrapper{6}).x

다음을 의미합니다.

& ( (&intwrapper{6}).x )

그러나 주소 연산자 &선택기 표현식 의 결과에 적용 되므로 “외부”괄호를 생략 할 수 있습니다 .

또한 백그라운드에서 다음이 발생합니다 (유효한 구문이기도합니다).

&(*(&intwrapper{6})).x

7) 도우미 익명 구조체 리터럴 사용

원칙은 사례 # 6과 동일하지만 익명 구조체 리터럴을 사용할 수도 있으므로 도우미 / 래퍼 구조체 유형 정의가 필요하지 않습니다.

instance7 := SomeType{
    SomeField: &(&struct{ x int64 }{7}).x,
}


답변

문제를 해결하기 위해 int64 변수의 주소를 반환하는 함수를 사용하십시오.

아래 코드에서는 f정수를 받아들이고 정수의 주소를 보유하는 포인터 값을 반환하는 함수 를 사용합니다 . 이 방법을 사용하면 위의 문제를 쉽게 해결할 수 있습니다.

type myStr struct {
    url *int64
}

func main() {
    f := func(s int64) *int64 {
        return &s
    }
    myStr{
        url: f(12345),
    }
}


답변