В Go компилятор иногда автоматически преобразовывает значение тика к указателю на этот тип. Если вызвать метод с pointer-receiver на значении, всё будет работать:
type User struct {
Name string
}
func (u *User) SetName(name string) {
u.Name = name
}
func (u User) PrintName() {
fmt.Println(u.Name)
}
var u User
u.SetName("Alice") // Go превратил это в (&u).SetName("Alice")
u.PrintName() // Обычный value-receiver
Но стоит подключить интерфейсы — и магия исчезает:
type Named interface {
SetName(string)
PrintName()
}
var u User
var n Named
n = &u // OK: *User реализует оба метода
n = u // Ошибка: User не имеет SetName
Почему так?
У
User (значения) в method set только методы с value-receiver. У *User — и value-, и pointer-receiver. Автоматическое «взятие адреса» при работе с интерфейсами запрещено, потому что интерфейс хранит копию значения, а не сам объект.Копия:
* неадресуемая,
* неизменяемая.
Если бы мы могли взять
&n.(User), получили бы указатель на временную копию внутри интерфейса, которая теряется при новом присваивании. Это небезопасно.Итог
* Интерфейсы всегда копируют значение.
* Копия не имеет адреса и не может изменяться.
* Поэтому Go не делает auto-addressing, и method set интерфейса и method set конкретного значения должны строго совпадать.