Почему SetName не работает?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package main import "fmt" type User struct { name string } func (u *User) SetName(name string) { u.name = name } func main() { var u *User u.SetName("Gopher") fmt.Println("Name:", u.name) } |
"Почему не паника? Почему это вообще работает?!"
@richie_mayert
Ваш код вызывает панику, и это нормально в таком случае. Проблема здесь в том, что вы пытаетесь вызвать метод SetName
на nil
указатель типа *User
. Конкретно в вашей программе переменная u
инициализируется как nil
, поскольку вы не использовали ни new(User)
, ни var u User
. Таким образом, когда вы вызываете u.SetName("Gopher")
, происходит паника с сообщением, что вы пытаетесь разыменовать nil
.
Тем не менее, в Go есть некоторая "поблажка" с методами, которые вызываются на нулевых указателях. Если метод не пытается разыменовать сам указатель или обойтись без обращения по указателю к любой его части, вызов метода может пройти без ошибки (но это не ваш случай, так как у вас происходит разыменование указателя u
для доступа и изменения поля name
).
Стоит исправить код следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
package main import "fmt" type User struct { name string } func (u *User) SetName(name string) { u.name = name } func main() { u := &User{} // Инициализируем указатель на экземпляр User u.SetName("Gopher") fmt.Println("Name:", u.name) } |
В этой исправленной версии вы создаёте новый экземпляр User
и инициализируете переменную u
так, что она указывает на него. Теперь вызовы методов SetName
и обращения к полю name
безопасны и не вызовут панику.