函数接收器的地址因方法而异

时间:2019-05-16 17:11:39

标签: go parameter-passing callstack function-call

我有以下代码。 https://play.golang.org/p/YAa6cgtA3Vo

在方法调用之间,接收器指针的地址有所不同。这令人困惑。谁能解释为什么会这样?我是否需要将指针作为参数传递给接收器,以保持相同的地址?

type myStruct struct {
    //struct content is irrelevant
}

func (ptrToStruct *myStruct) returnAddress() **myStruct {
    return &ptrToStruct
}

func (ptrToStruct *myStruct) method1() {
    addressOfPtr := ptrToStruct.returnAddress()
    fmt.Println(&ptrToStruct)
    fmt.Println(addressOfPtr)
    if &ptrToStruct != addressOfPtr {
        fmt.Println("Different addresses!")
    }
}

编辑:

我想要的是ptrToStruct的地址,而不是它的值。我知道我可以通过输入method1()addressOfPtr = &ptrToStruct中获得它,但是在我的用例中,returnAddress()方法中发生了一些逻辑,我需要它来那里。

1 个答案:

答案 0 :(得分:2)

这很简单:当您在某个地方var ms myStruct时, 调用ms.returnAddress()会将ms变量的地址传递给returnAddress,并且该地址将始终相同(这很容易验证-自己尝试一下)。

现在考虑到ptrToStruct定义中的returnAddress只是要传递给该方法的特殊参数,它的具体类型为*myStruct

此类型在内部只是一个整数—足够大,可以存储平台/ OS组合上任何内存位置的地址。

现在考虑执行调用ms.returnAddress()时,将使用ms变量的地址并将其写入传递给ptrToStruct的{​​{1}}参数中。 该参数也是一个变量-生存期等于函数调用的持续时间,并且仅在该函数的主体中可见。

此变量是由准备函数调用的代码在调用堆栈上自动创建的。 (所有其他方法参数也一样。)

因此,当您获取returnAddress的地址时,您将获取出现在调用堆栈上某个位置的变量的地址,该变量将在方法返回时消失。

现在考虑:

  • Go中的goroutine堆栈是可增长的(因此增长时可能会在内存中重定位);
  • 可以从不同的goroutine中调用一个方法(每个方法都有自己的堆栈);
  • 即使多次从同一个goroutine调用该方法,也可能在该goroutine执行的代码路径中的不同位置调用该方法。

以上所有情况可能导致ptrToStuct变量的地址在每次调用之间基本上是随机的。

(可能)您真正想要的只是按原样返回ptrToStruct的值,而不是返回地址。

希望这会有所帮助。 如果您不想真正了解ptrToStruct的出现和消失的方式,请考虑从this开始。