这是指针指针
package main
import "fmt"
func main() {
var num int
fmt.Println(&num) // 0x...0
makePointer(&num)
}
func makePointer(firstPointer *int) {
fmt.Println(firstPointer) // 0x...0
fmt.Println(&firstPointer) // 0x...1
makePointerToAPointer(&firstPointer)
}
func makePointerToAPointer(secondPointer **int) {
fmt.Println(secondPointer) // 0x...1
fmt.Println(&secondPointer) // 0x...2
}
你什么时候才能使用它?你可以正确地提出一些更容易做其他事情的事情,但这不是我所要求的。我真的想知道你会在哪个生产中使用它?
答案 0 :(得分:5)
指针的指针有时在函数参数中有意义;可能不是**int
,而是指向某个结构的指针的指针,您希望函数能够更改变量指向的对象,而不仅仅是更改结构的内容。例如,Go编译器的内部有一些函数采用**Node
(参见cmd / compile / internal / gc / racewalk.go)。
我自己也编写了一些函数**html.Node
;它们在一个HTML页面上运行,该页面可能已经或可能没有被解析为*html.Node
的树,并且它们可能需要或可能不需要解析页面 - 但如果它们这样做,我想保留已解析的树因此,我不必再次解析它。这些是在github.com/andybalholm/redwood/prune.go。
它们在没有多个返回值的语言中更常见,因为它们可以用作返回作为指针的附加值的方法。许多Objective-C方法将NSError**
作为最后一个参数,以便他们可以选择返回NSError*
。
答案 1 :(得分:4)
将指针传递给某个东西的目标是,如果有需要来修改指向的值。 (我们还使用指针来避免在传递时复制大型数据结构,但这仅用于优化。)
就像这个例子一样:
func main() {
var i int
fmt.Println(i)
inc(&i)
fmt.Println(i)
}
func inc(i *int) {
*i++
}
输出是预期的(在Go Playground上尝试):
0
1
如果inc()
的参数仅接收int
,则它只能修改副本而不能修改原始值,因此调用者不会观察到更改后的值。
指针指向某事物的指针也是如此。我们使用指向某事物的指针,如果我们需要修改指向的值,即指向指针。就像在这个例子中一样:
func main() {
var i *int
fmt.Println(i)
alloc(&i, 1)
fmt.Println(i, *i)
setToNil(&i)
fmt.Println(i)
}
func alloc(i **int, initial int) {
*i = new(int)
**i = initial
}
func setToNil(i **int) {
*i = nil
}
输出(在Go Playground上尝试):
<nil>
0x1040a130 1
<nil>
实际上没有使用指针指针的原因是因为修改指向的值可以通过返回值来替换,并在调用者处分配它:
func main() {
var i *int
fmt.Println(i)
i = alloc(1)
fmt.Println(i, *i)
i = setToNil()
fmt.Println(i)
}
func alloc(initial int) *int {
i := new(int)
*i = initial
return i
}
func setToNil() *int {
return nil // Nothing to do here, assignment happens at the caller!
}
输出相同(地址可能不同)(在Go Playground上尝试):
<nil>
0x1040a130 1
<nil>
这个变体更容易阅读和维护,所以这显然是必须修改指针值的函数的优势和广泛的替代。
在函数和方法只能有1个返回值的语言中,通常需要额外的&#34; work&#34;如果函数还想要返回除指针之外的其他值,例如将创建一个包装器以容纳多个返回值。但是由于Go支持多个返回值,因此指针指针基本上必须降为零,因为它可以替换为返回将被设置为指向指针的指针;并且它不需要额外的工作,也不会使代码的可读性降低。
这与内置append()
函数非常相似:它将值附加到切片。并且由于切片值发生变化(其长度增加,如果需要分配新的后备数组,其中的指针也可能会发生变化),append()
将返回您需要分配的新切片值(如果您想要保留新的切片。)
请参阅此相关问题,其中指向指针的指针(但也返回指针也可行/首选):Golang: Can the pointer in a struct pointer method be reassigned to another instance?
答案 2 :(得分:1)
以同样的方式,指向值的指针允许您在更改时为值的一致视图提供多个对相同值的引用,指向指针的指针允许您对一致视图具有多个对同一引用的引用当指针改变为指向内存中的不同位置时。
我不能说我曾经在Go中看到它在我能想到的实践中使用过。