Объясните концепцию методов в Go. В чем разница между получателем-значением и получателем-указателем?

Ответ

В Go метод — это функция, связанная с определенным типом. Этот тип называется получателем (receiver). Чаще всего методы определяются для структур, но их можно определить для любого именованного типа, кроме указателя или интерфейса.

Основное различие заключается в том, как метод получает доступ к данным получателя:

1. Получатель-значение (Value Receiver)

Метод работает с копией значения. Любые изменения внутри метода не затрагивают исходную переменную.

  • Когда использовать:
    • Когда метод не должен изменять исходную структуру.
    • Для небольших структур, копирование которых не является затратным.
    • Для обеспечения неизменяемости (immutability).
type Rectangle struct {
    Width, Height float64
}

// Метод с получателем-значением
// Работает с копией r
func (r Rectangle) Area() float64 {
    return r.Width * r.Height
}

2. Получатель-указатель (Pointer Receiver)

Метод работает с указателем на исходное значение, что позволяет изменять его.

  • Когда использовать:
    • Когда метод должен модифицировать исходную структуру.
    • Для больших структур, чтобы избежать затратного копирования при каждом вызове метода.
// Метод с получателем-указателем
// Работает с оригиналом r и может его изменять
func (r *Rectangle) Scale(factor float64) {
    r.Width *= factor
    r.Height *= factor
}

Ключевой момент: Go предоставляет синтаксический сахар. Если у вас есть переменная-значение r, вы можете вызвать метод с получателем-указателем r.Scale(2), и Go автоматически преобразует это в (&r).Scale(2). И наоборот.