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


111

*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 . 이것은 생성자 내부에서 사용하거나 리터럴 구조체 값을 지정하거나 다른 함수에 대한 인수로 사용할 수도 있습니다. 그러나 도우미 기능이나 다른 유형을 사용하는 것은 내가 찾고있는 솔루션이 아닙니다.


1
int에 대한 포인터는 int가 포인터와 같은 양의 공간을 차지하므로 불행히도 공간을 절약하지 못합니다. 일반적으로 가치가있는 것보다 더 복잡한 NULL 값을 추가합니다. 대부분의 경우 0이 좋습니다. 추가 값이 필요한 경우 "IsValidSomeField"부울도 작동하며 해당 부울에 더 나은 이름을 지정하면 가독성에 좋은 추가 값이 필요한 이유에 대해 자세히 설명 할 수 있습니다.
voutasaurus

3
예를 들어 패키지 포인터 를 사용할 수 있습니다 .var _ *int64 = pointer.Int64(64)
Xor

이것은 우리가 이것을 할 수있는 함수 또는 심지어 라이브러리를 작성해야하는 매우 유감입니다.
코코넛

답변:


222

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,
}

1
이것은 instance두 개의 다른 객체가 두 개의 다른를 가리킬 것이기 때문에 플레이스 홀더가있는 질문의 마지막 예제와 기능적으로 다릅니다 int64. 그러나 적절하게 목적을 충족 OPS 보인다 않습니다
라이언 이닝

2
이것은 내 질문에 확실히 대답합니다. 그러나 그것은 나를 매우 화나게 만드는 : &[]int64{2}[0]나는에서 상수의 설명에 따라 같은 느낌 blog.golang.org/constants해야 처럼 일을 &0.
ThisGuy

@RyanHaining 그리고 동일한 주소가 할당되는 것처럼 작동하면 어떻게 될까요? 두 개의 다른 instance객체가 같은 것을 가리키고 int64하나가 뾰족한 객체를 수정하면 둘 다 변경됩니다. 이제 동일한 리터럴을 사용하여 세 번째를 만들면 instance어떨까요? 동일한 주소가 이제 다른 int64값을 가리킬 것이므로 다른 주소를 사용해야하지만 처음 2 개의 경우 동일한 주소를 사용하는 이유는 무엇입니까?
icza

@icza 일반적으로 동일한 개체를 가리키는 것을 원하지 않을 것입니다. 나는 단지 차이점을 지적하고 있습니다.
Ryan Haining

4
@Conslo 상수는 컴파일 타임에 평가됩니다. 유효한 포인터 값, 유효한 메모리 주소는 런타임에만 존재하므로 상수와 동일하지 않습니다.
icza 2015-06-08

5

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

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

type myStr struct {
    url *int64
}

func main() {
    f := func(s int64) *int64 {
        return &s
    }
    myStr{
        url: f(12345),
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.