一尘不染

指针的指针(例如** int)有什么用例?

go

这是指向指针的指针

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

}

您何时真正使用此功能?您可以适当地提出一些可以更轻松地执行其他操作的方法,但这不是我要的。我真的想知道您将在生产中使用此功能吗?


阅读 190

收藏
2020-07-02

共1个答案

一尘不染

将指针传递给某物的目的是是否 需要 修改指向的值。(我们也使用指针来避免在传递时复制大型数据结构,但这只是为了优化。)

像这个例子一样:

func main() {
    var i int
    fmt.Println(i)
    inc(&i)
    fmt.Println(i)
}

func inc(i *int) {
    *i++
}

预期的输出(在Go Playground上尝试):

0
1

如果of的参数仅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>

此变体更易于阅读和维护,因此,这显然是必须修改指针值的函数的广泛青睐的替代方案。

在函数和方法只能有一个返回值的语言中,如果函数还希望返回除指针之外的其他值,则通常需要附加的“工作”,例如,将创建一个包装器来容纳多个返回值。但是由于Go支持多个返回值,因此指针指针的需求基本上降为零,因为可以用返回设置为指向指针的指针代替它。并且不需要额外的工作,也不会使代码的可读性降低。

这与内置append()函数非常相似:将值附加到切片。而且由于切片值发生变化(其长度增加,如果需要分配新的后备数组,其中的指针也可能会更改),因此append()返回您需要分配的新切片值(如果要保留新切片)

2020-07-02