다른 구조체에 값 또는 포인터로 액세스 할 때 어떤 차이가 있습니까?
언제 각각 하나씩 사용해야합니까?값 또는 포인터로 다른 구조체에 액세스
type foo_ struct {
st uint8
nd uint8
}
type bar struct {
rd uint8
foo foo_
}
type barP struct {
rd uint8
foo *foo_
}
다른 구조체에 값 또는 포인터로 액세스 할 때 어떤 차이가 있습니까?
언제 각각 하나씩 사용해야합니까?값 또는 포인터로 다른 구조체에 액세스
type foo_ struct {
st uint8
nd uint8
}
type bar struct {
rd uint8
foo foo_
}
type barP struct {
rd uint8
foo *foo_
}
type bar
의 변수를 선언하거나 할당하면 rd uint8
및 foo foo_
모두에 대해 메모리를 예약하고 초기화합니다. type foo_
의 변수 중 하나는 항상 변수 type bar
에 임베드됩니다. 당신이 선언하거나 type barP
의 변수를 할당하는 경우
var b bar // declare b
, 당신은 예약과 rd uint8
및 foo *foo_
모두 제로 메모리 초기화합니다. 0 값 포인터는 nil
포인터입니다. type foo_
의 변수가 할당되지 않습니다. 당신은 별도로해야합니다. 0 (foo == nil
) 또는 type foo_
의 변수 중 하나가 type barP
이라는 변수로 지정됩니다. type barP
의 변수는 다른 변수가 인 type foo_
의 동일 변수를 가리킬 수 있으며, 변수의 동일한 사본은 type foo_
입니다. 공유 사본에 대한 변경 사항은 공유 사본을 가리키는 모든 변수에서 볼 수 있습니다. 사용하는 하나의
var bp barP // declare bp
bp.foo = new(foo_) // allocate bp.foo
는 type barP
대 type bar
의 특성에 따라 달라집니다. 어떤 유형이 당신이 해결하려고하는 문제를 더 잘 반영하고 있습니까?
예를 들어,이 송장 문제를 고려해보십시오. 우리는 항상 청구서 수신 주소가 있습니다. 우리는 항상 돈을 요구할 것입니다. 그러나 청구서 수신 주소로 발송하는 경우가 있지만 항상 그렇지는 않습니다. 배송 주소가 nil
인 경우 청구서 수신 주소를 사용하십시오. 그렇지 않으면 별도의 운송 주소를 사용하십시오. 우리는 두 개의 창고를 보유하고 있으며 항상 하나 또는 다른 창고에서 출하합니다. 두 개의 창고 위치를 공유 할 수 있습니다. 주문이 창고에서 배송 될 때까지 인보이스를 보내지 않으므로 창고 위치는 결코 nil
이 아닙니다.
type address struct {
street string
city string
}
type warehouse struct {
address string
}
type invoice struct {
name string
billing address
shipping *address
warehouse *warehouse
}
답변은 언어와는 크게 관련이 없습니다. C의 동일한 문제는 동일한 문제가 있습니다.
값이 내장되어 있으면 (bar
처럼) 구조는 전체 하위 구조와 다른 부분을 보유 할만큼 충분히 큽니다.
barP
과 같은 값에 대한 포인터가 있으면 barP
유형의 구조가 동일한 foo
을 공유 할 수 있습니다. barP
중 하나가 foo
의 일부를 수정하면 동일한 위치를 가리키는 다른 모든 barP
구조에 영향을줍니다. 또한 주석에서 알 수 있듯이 barP
과 foo
이라는 두 개의 개별 객체를 일반 bar
유형과 대조하여 관리해야합니다.
일부 언어에서는 포인터가 매달 리거나 초기화되지 않은 값 등이 있는지 걱정해야합니다. Go는 가비지 수집되며 일반적으로 다른 언어보다 더 형식 안전합니다.
따라서 복수 barP
개체가 동일한 foo
개체를 공유하도록하려면 포인터를 사용하십시오. 그렇지 않으면 개체에 대한 포인터가 아니라 명시 적 멤버 개체를 사용하십시오.
는 Golang FAQ 지금의 차이를 요약
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
이 (효율이 지점은 또한 " Memory, variables in memory, and pointers"에 도시되어있다)먼저, 그리고 가장 중요한, 방법은 수신기을 수정해야합니까?
그렇다면 수신기는 포인터 여야합니다. 슬라이스와 맵은 참조 유형이므로 해당 스토리는 좀 더 미묘합니다. 예를 들어 메서드에서 슬라이스의 길이를 변경하려면 수신기가 여전히 포인터 여야합니다.
pointerMethod
이 필드가s
이면 호출자는 이러한 변경 사항을 볼 수 있지만 호출자의 인수 사본 (값 전달의 정의)을 사용하여valueMethod
이 호출되므로 호출자가 변경할 수 없습니다.
그런데 포인터 수신기는 자바의 상황과 동일합니다. 자바에서는 포인터가 커버 아래에 숨겨져 있습니다. 평범한 Go의 가치있는 수신기입니다.두 번째는 효율성입니다. 수신기가 큰 경우, 예를 들어 큰 구조체 인 경우 포인터 수신기를 사용하는 것이 훨씬 저렴합니다.
다음 일관성이다. 유형의 메소드 중 일부가 포인터 수신자를 가져야하는 경우 나머지도 있어야하므로 유형 세트 사용 방법에 관계없이 메소드 세트가 일관됩니다. 자세한 내용은 method sets 섹션을 참조하십시오.
'type barP'의 변수가 선언되거나 할당되면, foo의 초기 값은'nil' 포인터가됩니다. – peterSO