Идите структурировать литералы, почему этот адрес адресуемый?

Я читаю книгу "Язык программирования Go". Это очень хорошо для нас (скорее) опытных программистов и объясняет различия между пересечениями других языков - но я нашел случай, который я не до конца понимаю.

Я знаю C++ достаточно хорошо, и я понимаю, что Go называет (что бы в C++ называлось) rvalues ​​/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 буквальный во втором случае адресуемый?

Это особый случай для удобства, или я что-то упускаю из общей картины?

3 ответа

Решение

&T{} обозначения поясняются в разделе 4.4.1, Литералы структуры, на странице 103:

Поскольку структуры так часто обрабатываются с помощью указателей, можно использовать эту сокращенную запись для создания и инициализации переменной структуры и получения ее адреса:

pp := &Point{1, 2}

Это в точности эквивалентно

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

но &Point{1, 2} может использоваться непосредственно в выражении, таком как вызов функции.

Рад, что в противном случае вы наслаждаетесь книгой.

Это особый случай для удобства. Спецификация упоминает здесь исключение.

В качестве исключения из требования адресуемости, x также может быть (возможно заключенным в скобки) составным литералом.

Добавим немного больше деталей к ответу Mellow Marmot:

Spec: переменные:

Вызов встроенной функции newили взятие адреса составного литерала выделяет память для переменной во время выполнения. На такую ​​анонимную переменную ссылаются через (возможно, неявную) указатель косвенности.

Point{1, 1} является составным литералом, взяв его адрес создаст анонимную переменную под капотом, а результатом выражения будет адрес этой анонимной переменной.

Итак, как вы можете видеть технически, это переменная, к которой обращаются, поэтому она не нарушает это:

Только "переменные" [слова GOPL] являются адресуемыми.

Также ознакомьтесь с этим ответом, чтобы узнать, какие еще "полезности" или приемы вы можете сделать: как сделать литерал *int64 в Go?

Другие вопросы по тегам