user1781434
user1781434

Reputation:

Go struct literals, why is this one addressable?

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?

Upvotes: 5

Views: 1255

Answers (3)

Alan Donovan
Alan Donovan

Reputation: 514

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.

Upvotes: 6

icza
icza

Reputation: 417402

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: How do I do a literal *int64 in Go?

Upvotes: 2

Thundercat
Thundercat

Reputation: 120931

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.

Upvotes: 2

Related Questions