去结构文字,为什么这个可以解决?

时间:2016-11-24 19:17:57

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

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

我知道C ++足够好,并且我理解Go调用(在C ++中会调用什么)rvalues / xvalues" non-addressable"。只有"变量" [GOPL&#39的话]是可以寻址的。

好,公平;这很有意义。

因此,例如,这是非法的(根据第一次印刷中的第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字面值可以解决?

为方便起见,这是一个特例,还是我在大局中遗漏了什么?

3 个答案:

答案 0 :(得分:4)

为方便起见,这是一个特例。该规范提到异常here

  

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

答案 1 :(得分:4)

pp := &Point{1, 2} 符号在第4.4.1节“结构文字”中对此进行了解释:

  

因为结构通常通过指针处理,所以可以使用这种简写表示法来创建和初始化结构变量并获取其地址:

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

完全等同于

&Point{1, 2}
     

import Foundation class SomeClass {} var obj: SomeClass? = SomeClass() weak var weakObj = obj var array = [SomeClass?]() array.append(obj) print(obj, weakObj) //->Optional(SwiftArrayARC.SomeClass) Optional(SwiftArrayARC.SomeClass) array.removeFirst() obj = nil print(obj, weakObj) //->nil nil print(array) //->[] print(Unmanaged.passUnretained(weakObj!).toOpaque()) //=>fatal error: unexpectedly found nil while unwrapping an Optional value 可以直接在表达式中使用,例如函数调用。

很高兴你不喜欢这本书。

答案 2 :(得分:3)

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

Spec: Variables:

  

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

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

因此,从技术角度来看,它是一个被解决的变量,所以它不会违反这一点:

  

只有"变量" [GOPL&#39的话]是可以寻址的。

同时查看此答案,了解其他什么"好东西"或者你可以做的技巧:How do I do a literal *int64 in Go?