Что именно фиксирует метод-значение, полученное из интерфейсного значения, в момент его создания?
Метод-значение фиксирует текущий receiver — динамическое значение, находящееся в интерфейсе в момент получения метода. Последующее присваивание другого значения интерфейсной переменной не изменит receiver уже созданного метода.
Методы-значения появились как часть общей модели методов Go и позволяют передавать вызов метода как обычную функцию, например в callback или горутину. Такой подход уменьшает связанность кода, но требует понимать, что receiver сохраняется не на момент вызова, а на момент получения метода.
Ошибочное ожидание возникает, когда метод извлекают из интерфейсной переменной, затем меняют содержимое этой переменной и рассчитывают, что вызов сохранённого метода обратится к новому объекту. В результате вызов выполняется для прежнего receiver, что может привести к изменению не того объекта или к неожиданному поведению в асинхронном коде.
При выражении вида метод := интерфейснаяПеременная.Метод Go вычисляет receiver и сохраняет его вместе с методом. Если динамическое значение является указателем, сохраняется копия указателя; изменение объекта по этому указателю будет видно, но переназначение самой интерфейсной переменной — нет.
Если receiver имеет тип-значение, метод-значение сохраняет копию этого значения. Поэтому последующие изменения исходной переменной не повлияют на сохранённый receiver. Для указателя результат обычно выглядит иначе: копируется адрес, а не состояние объекта.
Метод add сохранил receiver &a. Переприсваивание x значением &b меняет только интерфейсную переменную x, поэтому вызов увеличивает счётчик a.
Главный компромисс — удобство передачи callback против менее очевидного времени фиксации receiver. При создании callback в цикле или передаче его в горутину нужно явно проверить, какой объект был сохранён.
Сервис регистрирует обработчики через интерфейс Handler. Разработчик получает метод обработчика, затем заменяет реализацию в переменной конфигурации и ожидает, что ранее зарегистрированный callback начнёт вызывать новую реализацию.
Можно каждый раз обращаться к методу через актуальную интерфейсную переменную. Это выбирает новую реализацию, но усложняет callback и создаёт зависимость от изменяемого состояния.
Можно заранее сохранить метод-значение. Такой вариант проще и безопаснее для регистрации обработчика: callback стабильно связан с конкретным receiver. Он выбран, если обработчик должен оставаться неизменным; если же нужна динамическая маршрутизация, следует сохранять функцию, которая при каждом вызове читает актуальную реализацию.
Нет. Receiver вычисляется при создании метода-значения и больше не связан с последующими присваиваниями интерфейсной переменной. Если в интерфейсе был указатель, сохранённый указатель остаётся тем же.
Потому что для pointer receiver сохраняется копия указателя. Изменение полей объекта через этот или другой указатель меняет один и тот же объект, тогда как замена указателя или интерфейсного значения создаёт уже другую связь.
Метод-значение уже содержит receiver и вызывается без явной передачи объекта. Method expression превращает метод в функцию, где receiver становится обычным первым аргументом; объект выбирается в момент вызова. Поэтому method expression удобнее, когда receiver нужно определять динамически, а метод-значение — когда связь с конкретным receiver должна быть зафиксирована заранее.