Ответ
Разница между pointer receiver
(получатель-указатель) и value receiver
(получатель-значение) заключается в том, получает ли метод указатель на исходный экземпляр или его полную копию.
Pointer Receiver (func (p *T) Method()
)
- Изменение состояния: Метод получает указатель на исходный объект. Это позволяет изменять состояние объекта внутри метода.
- Производительность: Эффективен для больших структур, так как в метод передается только указатель (обычно 4 или 8 байт), а не копируется вся структура.
- Работа с
nil
: Метод может быть безопасно вызван наnil
-указателе. Внутри метода можно добавить проверкуif p == nil
.
Value Receiver (func (v T) Method()
)
- Неизменяемость (Immutability): Метод получает копию объекта. Все изменения внутри метода затрагивают только эту копию и не влияют на исходный объект. Это гарантирует, что метод не изменит вызывающий его экземпляр.
- Производительность: Может быть неэффективен для больших структур из-за накладных расходов на копирование.
- Работа с
nil
: Вызов метода наnil
-указателе приведет к панике.
Пример:
package main
import "fmt"
type User struct {
Name string
}
// Pointer receiver: может изменять исходный объект
func (u *User) SetName(newName string) {
if u == nil {
fmt.Println("Нельзя изменить nil-пользователя")
return
}
u.Name = newName
}
// Value receiver: работает с копией
func (u User) Greet() {
fmt.Printf("Привет, %s!n", u.Name)
}
func main() {
user := User{Name: "Алекс"}
user.Greet() // Привет, Алекс!
user.SetName("Иван") // Изменяем исходный объект
user.Greet() // Привет, Иван!
var nilUser *User
nilUser.SetName("Петр") // Безопасно, сработает проверка на nil
// nilUser.Greet() // Приведет к панике
}
Рекомендации (Rule of Thumb):
- Используйте pointer receiver, если метод должен изменять состояние объекта или если структура велика.
- Используйте value receiver, если метод не изменяет состояние, а структура маленькая (например, слайс,
time.Time
) или вы хотите гарантировать неизменяемость. - Для консистентности, если хотя бы один метод типа имеет pointer receiver, остальные методы также должны иметь pointer receiver.