【问题标题】:Go struct literals, why is this one addressable?Go struct literals,为什么这是可寻址的?
【发布时间】:2016-11-24 19:17:56
【问题描述】:

我正在阅读《Go 编程语言》这本书。这对我们(相当)有经验的程序员来说非常好,并解释了其他语言交集之间的差异——但我发现了一个我不完全理解的案例。

我非常了解 C++,并且我理解 Go 调用(在 C++ 中将被称为)右值/xvalues“不可寻址”。只有“变量” [GOPL 的话] 是可寻址的。

好的,很公平;这是有道理的。

因此,例如,这是非法的(根据第 159 页的第一次印刷)

Point{1, 2}.ScaleBy(2) // compile error: can't take address of Point literal

因为(*Point).ScaleBy*Point 作为接收器参数,而Point 文字是不可寻址的。

(如果你没有读过这本书,Point 是一个带有字段X, Y float64 的结构体。

然而,在第 162 页,我们有

type ColoredPoint struct {
    *Point
    Color color.RGBA
}

p := ColoredPoint(&Point{1, 1}, red)
// ...more code ...

这显然是有效的并且会编译。

问题:

为什么第二种情况下的 Point 文字是可寻址的?

这是为了方便起见的特殊情况,还是我在大局中遗漏了什么?

【问题讨论】:

    标签: pointers go struct language-lawyer composite-literals


    【解决方案1】:

    &T{} 符号在第 103 页的第 4.4.1 节,结构文字中进行了解释:

    由于结构体通常通过指针来处理,因此可以使用这种简写符号来创建和初始化结构体变量并获取其地址:

    pp := &Point{1, 2}
    

    完全等价于

    pp := new(Point)
    *pp = Point{1, 2}
    

    &Point{1, 2} 可以直接在表达式中使用,例如函数调用。

    很高兴你喜欢这本书。

    【讨论】:

    • 我真的很喜欢它!虽然我正在阅读它(或多或少地匆忙),因为我很可能很快就会找到一份全职编写 Go 代码的工作。一定漏掉了这部分。我认为这与 K&D.... 我的意思是 K&R。 ;-) 再次感谢!
    • 它是否相当于var pp *Point; *pp = Point{1, 2} 而不是pp := new(Point)?新创建的零值Point 对象被Point{1, 2} 覆盖,不是吗? (是的,是的,我敢问 Go 书的作者 :-))
    【解决方案2】:

    为方便起见,这是一个特殊情况。规范提到了 here 的异常。

    作为可寻址性要求的一个例外,x 也可以是(可能带括号的)复合文字。

    【讨论】:

    • 谢谢,这显然是对我问题的直接回答。我会尽快标记它。
    【解决方案3】:

    为 Mellow Marmot 的回答添加更多细节:

    Spec: Variables:

    调用内置函数new 或获取composite literal 的地址会在运行时为变量分配存储空间。这种匿名变量通过(可能是隐式的)pointer indirection 引用。

    Point{1, 1} 是一个复合字面量,取它的地址会在底层创建一个匿名变量,表达式的结果就是这个匿名变量的地址。

    所以你可以从技术上看到它是一个被处理的变量,所以它不违反这个:

    只有“变量” [GOPL 的话] 是可寻址的。

    还可以查看此答案,了解您可以做哪些其他“好东西”或技巧:How do I do a literal *int64 in Go?

    【讨论】:

    • 感谢您添加到已接受的答案中!非常有用的信息。
    猜你喜欢
    • 2013-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-11-05
    • 1970-01-01
    • 2019-11-05
    • 1970-01-01
    • 1970-01-01
    • 2012-04-11
    相关资源
    最近更新 更多