Самый простой способ думать об обеих функциях состоит в том, что в функции t2
вы изменяете поле структуры, используя указатель на базовую структуру.В функции t
вы изменяете весь базовый объект (int).
На самом деле тот факт, что вы можете написать p.X
, на самом деле просто приятная вещь.В таких языках, как C, вы можете использовать p.X
, только если вы работаете с переменной без указателя.Для указателей вы должны были либо использовать p->X
, обозначая, что вы обращались к полю с помощью косвенного обращения, либо действительно разыменовывать указатель ((*p).X
).
Внутренне go по-прежнему делает то же самое, он просто позволяет вамчтобы исключить явное разыменование, и это устраняет необходимость в операторе косвенного обращения.
Обе функции, однако, не эквивалентны.Point
- это структура с одним или несколькими полями.Другой тип - *int
, int - это одно скалярное значение.Чтобы сделать t2
эквивалентным (и переназначить весь базовый объект), вам придется изменить код на идентичный тому, что вы должны сделать в случае *int
:
func t2(p *Point) {
*p = Point{
X: 200,
Y: p.Y,
}
}
Согласно комментарию ниже: версия TL; DR заключается в том, что вам не нужно явно разыменовывать указатель на тип структуры, если вы обращаетесь к одному из его полей.Вы должны были сделать это в C / C ++, но компилятор go позаботится об этом за вас.Получается, что вы используете переменную типа указателя и компилируете p.X
так же, как компилятор C компилирует p->X
.Следовательно, вам не нужно явно разыменовывать p
.
Вам все равно придется писать *p.X
, если вы объявили Point
как:
type Point struct {
X *int
}
Поскольку выражение p.X
соответствует операнду типа *int
, который должен обрабатываться соответствующим образом.