Go结构体字面量,为什么这个是可寻址的?

huangapple go评论78阅读模式
英文:

Go struct literals, why is this one addressable?

问题

我正在阅读《The Go Programming Language》这本书。对于我们这些有经验的程序员来说,它非常好,可以解释其他语言之间的差异。但是我发现了一个我不完全理解的情况。

我对C++有足够的了解,我知道在Go中,Go将(在C++中称为)rvalues/xvalues称为“非可寻址的”。只有“变量”(GOPL的说法)是可寻址的。

好吧,这是有道理的。

因此,例如,根据第一版第159页的说法,以下代码是非法的:

Point{1, 2}.ScaleBy(2) // 编译错误:无法获取Point字面量的地址

因为(*Point).ScaleBy需要一个*Point作为接收器参数,而Point字面量是非可寻址的。

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

然而,在第162页,我们有以下代码:

type ColoredPoint struct {
    *Point
    Color color.RGBA
}

p := ColoredPoint(&Point{1, 1}, red)
// ...更多代码...

这显然是有效的,并且可以编译通过。

问题:

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

这是为了方便而特殊处理的,还是我在整体上理解有误?

英文:

I am reading the book "The Go Programming Language". It is very good for us (rather) experienced programmers and explains the differences between the intersection of other languages -- but I've found a case which I do not understand fully.

I know C++ sufficiently good, and I understand that Go calls (what in C++ would be called) rvalues/xvalues "non-addressable". Only "variables" [GOPL's words] are addressable.

OK, fair enough; it makes sense.

And therefore, for instance, this is illegal (according to page 159 in the first printing)

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

because (*Point).ScaleBy takes a *Point as a receiver argument, and a Point literal is non-addressable.

(If you haven't read the book, Point is a struct with the fields X, Y float64.

However, on page 162, we have

type ColoredPoint struct {
    *Point
    Color color.RGBA
}

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

which apparently is valid and will compile.

Question:

Why is the Point literal in the second case addressable?

Is it a special case for convenience, or am I missing something in the big picture?

答案1

得分: 6

&T{} 表示法在第4.4.1节的“结构体字面量”中有解释,位于第103页:

> 由于结构体通常通过指针处理,因此可以使用这种简写表示法来创建和初始化结构体变量并获取其地址:
>
> pp := &Point{1, 2}
>
> 它与以下代码完全等效:
>
> pp := new(Point)
> *pp = Point{1, 2}
>
> 但是 &Point{1, 2} 可以直接在表达式中使用,例如函数调用。

很高兴你对这本书其他方面感到满意。

英文:

The &T{} notation is explained in Section 4.4.1, Struct Literals, on page 103:

> Because structs are so commonly dealt with through pointers, it’s possible to use this shorthand notation to create and initialize a struct variable and obtain its address:
>
> pp := &Point{1, 2}
>
> It is exactly equivalent to
>
> pp := new(Point)
> *pp = Point{1, 2}
>
> but &Point{1, 2} can be used directly within an expression, such as a function call.

Glad you're otherwise enjoying the book.

答案2

得分: 2

这是为了方便而特殊处理的情况。规范在这里提到了这个例外情况(https://golang.org/ref/spec#Address_operators)。

作为对可寻址要求的例外情况,x也可以是一个(可能带括号的)复合字面量。

英文:

It's a special case for convenience. The spec mentions the exception here.

> As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.

答案3

得分: 2

为Mellow Marmot的答案添加一些细节:

规范:变量:

调用内置函数new或获取复合字面量的地址会在运行时为变量分配存储空间。这样一个匿名变量通过(可能是隐式的)指针间接引用来引用。

Point{1, 1}是一个复合字面量,获取它的地址将在幕后创建一个匿名变量,表达式的结果将是这个匿名变量的地址。

因此,从技术上讲,它是一个被寻址的_变量_,所以它不违反这个规定:

> 只有_“变量”_(GOPL的说法)是可寻址的。

还可以查看这个答案,了解其他“好东西”或技巧:https://stackoverflow.com/questions/30716354/how-do-i-do-a-literal-int64-in-go/30716481#30716481

英文:

Adding a little more detail to Mellow Marmot's answer:

Spec: Variables:

> Calling the built-in function new or taking the address of a composite literal allocates storage for a variable at run time. Such an anonymous variable is referred to via a (possibly implicit) pointer indirection.

Point{1, 1} is a composite literal, taking its address will create an anonymous variable under the hood, and the result of the expression will be the address of this anonymous variable.

So as you can see technically it's a variable that is addressed, so it does not violate this:

> Only "variables" [GOPL's words] are addressable.

Also check out this answer to see what other "goodies" or tricks you can do: https://stackoverflow.com/questions/30716354/how-do-i-do-a-literal-int64-in-go/30716481#30716481

huangapple
  • 本文由 发表于 2016年11月25日 03:17:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/40793289.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定