Почему 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 безопасны и не вызовут панику.