Зачем нужны «ссылочные» методы и почему они не удовлетворяют интерфейсам?

В языке программирования Go существуют два типа методов: значение и ссылка (также называемые "ссылочными" методами). Оба типа методов могут быть определены для пользовательских типов данных. Зачем же нужны "ссылочные" методы и почему они не удовлетворяют интерфейсам?

Первоначально стоит разобраться в понятии "значение" и "ссылка" в Go. При работе с типами данных Go предоставляет возможность передавать аргументы по значению или по ссылке. Если аргумент передается по значению, то копия этого значения создается в вызываемой функции или методе, и любые изменения, сделанные внутри функции или метода, не влияют на исходное значение. Если же аргумент передается по ссылке, то передается не само значение, а ссылка на него. Таким образом, любые изменения, сделанные внутри функции или метода, будут отображаться на исходном значении.

Когда мы говорим о "ссылочных" методах в Go, мы говорим о методах, которые оперируют с указателями на типы данных. Такие методы имеют следующую сигнатуру: func (p *Type) MethodName(). Преимущество таких методов заключается в том, что они могут изменять состояние самого объекта, на который указывает указатель. То есть, если мы вызовем метод на указателе, то будем работать с самим объектом, а не его копией.

Теперь, почему "ссылочные" методы не удовлетворяют интерфейсам. В Go интерфейсы являются наборами методов, и любой тип данных, удовлетворяющий всем методам интерфейса, автоматически является реализатором этого интерфейса. Однако, для того чтобы тип данных удовлетворял интерфейсу, он должен соответствовать его сигнатуре, а это значит, что все методы интерфейса должны быть определены для самого типа, а не для указателя на этот тип.

Например, у нас есть интерфейс Shape, который имеет метод Area() float64. Теперь, если у нас есть тип данных Rectangle и метод Area() определен для его указателя func (r *Rectangle) Area() float64, то сам тип Rectangle не является реализатором интерфейса Shape. Чтобы сделать это, нам необходимо определить метод Area() для самого типа Rectangle, не указателя.

Понимание разницы между использованием значений и указателей очень важно при определении методов для типов данных в Go. Использование "ссылочных" методов позволяет эффективно менять состояние объектов типа данных и влиять на исходные значения, но эти методы не могут быть использованы для удовлетворения интерфейсов. Вместо этого, при необходимости использования типа данных в качестве реализатора интерфейса, необходимо определить методы для самого типа, а не для указателей на него.