Go에서 포인터를 사용하는 이유는 무엇입니까?


100

Go의 포인터가 함수 인수의 변형을 허용한다는 것을 알고 있지만 참조 (적절한 const 또는 가변 한정자 포함) 만 채택했다면 더 간단하지 않았을 것입니다. 이제 포인터와 맵 및 채널과 같은 일부 내장 유형에 대해 암시 적으로 참조로 전달합니다.

내가 뭔가를 놓치고 있거나 Go의 포인터가 불필요한 복잡성입니까?


1
다음은 명확히하는 데 도움이되는 질문입니다. stackoverflow.com/questions/795160/… 참조를 값으로 전달하는 것과 실제로 참조로 전달하는 것에는 차이가 있습니다.
R. Martinho Fernandes

1
참고 : 문제는 Java에 관한 것이지만 여기에도 적용됩니다.
R. Martinho Fernandes

1
"지도 및 채널과 같은 일부 내장 유형의 경우 암시 적으로 참조로 전달합니다." 아니요, Go에서는 모든 것이 가치에 의해 전달됩니다. 일부 유형은 내부 변경 가능 상태를 갖기 때문에 참조 유형입니다 (비공식적으로 설명 됨).
newacct 2012

이 질문의 문제는 "참조"가 잘 정의 된 속성을 가진 단일 항목이 아니라는 것입니다. "참조"라는 용어는 매우 모호합니다. 우리는 답변에서 얼마나 많은 사람들이 "참조"라는 단어로 다른 것을 읽었는지 볼 수 있습니다. 따라서이 질문은 Go 포인터와 질문이 염두에두고있는 참조간에 정확히 어떤 차이점이 있는지 자세히 설명해야합니다.
mtraceur

답변:


36

http://www.golang-book.com/8 에서 가져온 예를 정말 좋아합니다 .

func zero(x int) {
    x = 0
}
func main() {
    x := 5
    zero(x)
    fmt.Println(x) // x is still 5
}

대조적으로

func zero(xPtr *int) {
    *xPtr = 0
}
func main() {
    x := 5
    zero(&x)
    fmt.Println(x) // x is 0
}

42
질문은 "왜 우리는 참조 대신 포인터 가지고 있는가"였고이 예제가 참조와 함께 작동하지 않는 이유를 이해할 수 없습니다.
AndreKR

@AndreKR 참조로 전달할 것인지 값으로 전달할 것인지 선택할 수 있기 때문입니다. 둘 다 바람직 할 수있는 몇 가지 경우가 있습니다.
JDSweetBeat dec.

9
@DJMethaneMan "포인터 대 값에 의한 전달"이 아니라 "포인터 대 참조"입니다!
AndreKR

부수적으로 C # 2.0에서는 "ref"키워드를 통해 참조에 의한 전달이 추가되었습니다. 우리는 포인터 포인터 포인터를 가질 수 있기 때문에 물론 포인터는 ... 아직 어떤 경우에 더 편리합니다
로비 팬

Go가 가장 쉬운 인기 언어 중 하나라는 것을 이해하지 못했지만 이러한 "기능"이 포함되어 있습니다. 적어도 여기에서 이것을 지적하는 사람들에게는 혼란스럽고 불필요 해 보입니다.
Akito

33

포인터는 여러 가지 이유로 유용합니다. 포인터를 사용하면 메모리 레이아웃을 제어 할 수 있습니다 (CPU 캐시의 효율성에 영향을 미침). Go에서 모든 멤버가 연속 메모리에있는 구조를 정의 할 수 있습니다.

type Point struct {
  x, y int
}

type LineSegment struct {
  source, destination Point
}

이 경우 Point구조체는 LineSegment구조체 내에 포함됩니다 . 그러나 항상 데이터를 직접 포함 할 수는 없습니다. 이진 트리 또는 연결 목록과 같은 구조를 지원하려면 일종의 포인터를 지원해야합니다.

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode
}

Java, Python 등은 복합 유형을 임베드 할 수 없기 때문에이 문제가 없으므로 임베딩과 포인팅을 구문 적으로 구분할 필요가 없습니다.

Go 포인터로 해결 된 Swift / C # 구조체 문제

이를 달성하기위한 가능한 대안을 구별하는 것이다 structclassC # 및 스위프트처럼. 그러나 여기에는 한계가 있습니다. 일반적으로 함수가 구조체를 inout매개 변수로 사용하여 구조체 복사를 방지하도록 지정할 수 있지만 구조체에 대한 참조 (포인터)를 저장할 수는 없습니다. 즉, 풀 할당자를 만드는 데 유용하다고 생각되면 구조체를 참조 유형으로 처리 할 수 ​​없습니다 (아래 참조).

커스텀 메모리 할당 자

포인터를 사용하여 고유 한 풀 할당자를 만들 수도 있습니다 (원칙을 보여주기 위해 많은 검사를 제거하여 매우 단순화 됨).

type TreeNode {
  value int
  left  *TreeNode
  right *TreeNode

  nextFreeNode *TreeNode; // For memory allocation
}

var pool [1024]TreeNode
var firstFreeNode *TreeNode = &pool[0] 

func poolAlloc() *TreeNode {
    node := firstFreeNode
    firstFreeNode  = firstFreeNode.nextFreeNode
    return node
}

func freeNode(node *TreeNode) {
    node.nextFreeNode = firstFreeNode
    firstFreeNode = node
}

두 값 바꾸기

포인터를 사용하면 swap. 그것은 두 변수의 값을 바꾸는 것입니다.

func swap(a *int, b *int) {
   temp := *a
   *a = *b
   *b = temp
}

결론

Java는 Google과 같은 곳에서 시스템 프로그래밍을위한 C ++를 완전히 대체 할 수 없었습니다. 부분적으로는 메모리 레이아웃 및 사용을 제어 할 수있는 능력이 없기 때문에 성능을 동일한 수준으로 조정할 수 없기 때문입니다 (캐시 누락은 성능에 상당한 영향을 미침). Go는 많은 영역에서 C ++를 대체하는 것을 목표로하고 있으므로 포인터를 지원해야합니다.


7
C #에서는 참조로 구조체를 전달할 수 있습니다. "ref"및 "out"키워드를 참조하십시오.
olegz

1
좋아요, 그것은 Swift와 같습니다. 내 예를 업데이트하는 방법에 대해 생각할 것입니다.
Erik Engheim

29

참조는 재 할당 할 수 없지만 포인터는 지정할 수 있습니다. 이것만으로도 참조를 사용할 수없는 많은 상황에서 포인터가 유용합니다.


17
참조를 재 할당 할 수 있는지 여부는 언어 별 구현 문제입니다.
crantok

28

Go는 간결하고 미니멀 한 언어로 설계되었습니다. 따라서 값과 포인터로 시작되었습니다. 나중에 필요에 따라 일부 참조 유형 (슬라이스, 맵 및 채널)이 추가되었습니다.


Go 프로그래밍 언어 : 언어 디자인 FAQ : 배열이 값인 반면 맵, 슬라이스 및 채널이 참조되는 이유는 무엇입니까?

"이 주제에 대한 많은 역사가 있습니다. 초기에는 맵과 채널이 구문 상 포인터 였고 비 포인터 인스턴스를 선언하거나 사용하는 것이 불가능했습니다. 또한 배열이 작동하는 방식에 어려움을 겪었습니다. 결국 우리는 엄격한 분리를 결정했습니다. 포인터와 값의 증가로 인해 언어를 사용하기가 더 어려워졌습니다. 배열의 참조 형식을 처리하는 슬라이스를 포함한 참조 유형을 도입하여 이러한 문제를 해결했습니다. 참조 유형은 언어에 약간의 유감스러운 복잡성을 추가하지만 사용성에 큰 영향을 미칩니다. Go는 더 생산적이고 편안한 언어를 도입했습니다. "


빠른 컴파일은 Go 프로그래밍 언어의 주요 디자인 목표입니다. 비용이 있습니다. 피해 중 하나는 변수 (기본 컴파일 시간 상수 제외)와 매개 변수를 불변으로 표시하는 기능입니다. 요청되었지만 거절되었습니다.


golang-nuts : go language. 약간의 피드백과 의심.

"형 시스템에 const를 추가하면 모든 곳에 나타나도록 강제하고 무언가 변경되면 모든 곳에서 제거해야합니다. 어떤 식 으로든 불변 객체를 표시하는 데 약간의 이점이있을 수 있지만, const 유형 한정자는 제대로 작동하지 않는다고 생각합니다. 토고."


FWIW, Go의 "참조 유형"도 다시 할당 할 수 있습니다. 암시 적 포인터와 비슷합니까?
Matt Joiner

1
포인터 (및 길이, 용량 등)를 포함하는 구조체의 특수 구문입니다.
mk12 2013-07-15
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.