Почему SetName не работает?

Пользователь

от richie_mayert , в категории: Golang , 4 месяца назад

Почему 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)
}

"Почему не паника? Почему это вообще работает?!"

Facebook Vk Ok Twitter LinkedIn Telegram Whatsapp

1 ответ

Пользователь

от nelle , месяц назад

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