我知道Go中的指针允许变量函数的参数,但如果它们只采用了引用(使用适当的const或可变限定符),它就不会更简单。现在我们有了指针和一些内置类型,如地图和通道隐式传递参考。
我是否遗漏了某些内容或指向Go只是一个不必要的并发症?
答案 0 :(得分: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
}
答案 1 :(得分:32)
无法重新分配引用,而指针可以。仅这一点就可以在许多不能使用引用的情况下使用指针。
答案 2 :(得分:31)
由于多种原因,指针很有用。指针允许控制内存布局(影响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#和Swift。但这确实有局限性。虽然您通常可以指定函数将结构作为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 ++,因此需要支持指针。
答案 3 :(得分:27)
Go旨在成为一种简洁,极简主义的语言。因此,它始于值和指针。之后,根据需要,添加了一些参考类型(切片,地图和通道)。
“关于这个主题有很多历史。早期,地图和通道都是语法指针,不可能声明或使用非指针实例。此外,我们还在努力解决数组应该如何工作。最后我们决定指针和值的严格分离使得语言难以使用。引入引用类型(包括处理数组引用形式的切片)解决了这些问题。引用类型为语言增加了一些令人遗憾的复杂性,但它们对可用性有很大影响:当它们被引入时,Go变得更加高效,舒适。“
快速编译是Go编程语言的主要设计目标;这有其成本。其中一个伤员似乎是将变量(基本编译时常量除外)和参数标记为不可变的能力。已被要求,但拒绝了。
golang-nuts : go language. Some feedback and doubts.
“将const添加到类型系统会强制它出现在任何地方,并且 如果有什么变化,强制一个人去除它。在那里时 以某种方式标记对象不可变可能有些好处,我们不这样做 认为const类型限定符是要走的路。“