Go의 포인터가 함수 인수의 변형을 허용한다는 것을 알고 있지만 참조 (적절한 const 또는 가변 한정자 포함) 만 채택했다면 더 간단하지 않았을 것입니다. 이제 포인터와 맵 및 채널과 같은 일부 내장 유형에 대해 암시 적으로 참조로 전달합니다.
내가 뭔가를 놓치고 있거나 Go의 포인터가 불필요한 복잡성입니까?
Go의 포인터가 함수 인수의 변형을 허용한다는 것을 알고 있지만 참조 (적절한 const 또는 가변 한정자 포함) 만 채택했다면 더 간단하지 않았을 것입니다. 이제 포인터와 맵 및 채널과 같은 일부 내장 유형에 대해 암시 적으로 참조로 전달합니다.
내가 뭔가를 놓치고 있거나 Go의 포인터가 불필요한 복잡성입니까?
답변:
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
}
포인터는 여러 가지 이유로 유용합니다. 포인터를 사용하면 메모리 레이아웃을 제어 할 수 있습니다 (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 등은 복합 유형을 임베드 할 수 없기 때문에이 문제가 없으므로 임베딩과 포인팅을 구문 적으로 구분할 필요가 없습니다.
이를 달성하기위한 가능한 대안을 구별하는 것이다 struct
및 class
C # 및 스위프트처럼. 그러나 여기에는 한계가 있습니다. 일반적으로 함수가 구조체를 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 ++를 대체하는 것을 목표로하고 있으므로 포인터를 지원해야합니다.
참조는 재 할당 할 수 없지만 포인터는 지정할 수 있습니다. 이것만으로도 참조를 사용할 수없는 많은 상황에서 포인터가 유용합니다.
Go는 간결하고 미니멀 한 언어로 설계되었습니다. 따라서 값과 포인터로 시작되었습니다. 나중에 필요에 따라 일부 참조 유형 (슬라이스, 맵 및 채널)이 추가되었습니다.
Go 프로그래밍 언어 : 언어 디자인 FAQ : 배열이 값인 반면 맵, 슬라이스 및 채널이 참조되는 이유는 무엇입니까?
"이 주제에 대한 많은 역사가 있습니다. 초기에는 맵과 채널이 구문 상 포인터 였고 비 포인터 인스턴스를 선언하거나 사용하는 것이 불가능했습니다. 또한 배열이 작동하는 방식에 어려움을 겪었습니다. 결국 우리는 엄격한 분리를 결정했습니다. 포인터와 값의 증가로 인해 언어를 사용하기가 더 어려워졌습니다. 배열의 참조 형식을 처리하는 슬라이스를 포함한 참조 유형을 도입하여 이러한 문제를 해결했습니다. 참조 유형은 언어에 약간의 유감스러운 복잡성을 추가하지만 사용성에 큰 영향을 미칩니다. Go는 더 생산적이고 편안한 언어를 도입했습니다. "
빠른 컴파일은 Go 프로그래밍 언어의 주요 디자인 목표입니다. 비용이 있습니다. 피해 중 하나는 변수 (기본 컴파일 시간 상수 제외)와 매개 변수를 불변으로 표시하는 기능입니다. 요청되었지만 거절되었습니다.
golang-nuts : go language. 약간의 피드백과 의심.
"형 시스템에 const를 추가하면 모든 곳에 나타나도록 강제하고 무언가 변경되면 모든 곳에서 제거해야합니다. 어떤 식 으로든 불변 객체를 표시하는 데 약간의 이점이있을 수 있지만, const 유형 한정자는 제대로 작동하지 않는다고 생각합니다. 토고."