Я понял это.Короче, я испортил две концепции.У меня было много путаницы, поэтому давайте разберем ее, начав с моего последнего замечания об автоматической разыменовке указателя.
Основная проблема, с которой я столкнулся, заключалась в том, что компилятор с удовольствием применил &
оператор для вас.Дело в том, что бывают моменты, когда это имеет смысл, а иногда нет (см. Ниже).
p := Person{"Old"}
var iface I = p
p.rename("New") // Can safely be rewritten to (&p).rename("New")
iface.rename("New") // Cannot rewrite (&iface != &p)
Вот почему имеет смысл запретить присваивать значение интерфейс, если только указатель на это значение удовлетворяет интерфейсу.Вы не можете просто вернуть адрес исходной переменной, когда она назначена интерфейсу, но вы можете это сделать, когда она является переменной действительного типа.Теперь, это все еще оставило меня в замешательстве по этому поводу:
p := Person{"Name"}
var iface I = &p // No error
То, что я получил от этого, в основном это то, что ... Go просто работает таким образом. Этот пост описывает наборы методов.Я был сбит с толку словом "адресуемый".Чтобы объяснить мою путаницу, у меня сложилось впечатление, что компилятор делал следующую вставку, когда указатель хранился, но было необходимо значение (что не имело бы смысла):
p := &Person{"Name"}
var iface I = p
p.rename() /* becomes */ (*p).rename()
iface.rename() /* becomes */ (*iface).rename()
Выполнение методавызов - это многошаговый процесс с точки зрения компилятора;простое добавление *
перед именем переменной может показаться далеко идущим, но есть еще больше переменных, которые можно скопировать из памяти и поместить в стек и т. д. В действительности, разыменование переменной самостоятельно не «делает» ничего длякомпилятор.В обоих случаях необходимо перейти в это место и скопировать то, что там есть.Физическое написание *
- это, с точки зрения Go, всего лишь указание компилятору делать то, что он уже собирается делать, потому что метод получателя значения ожидает значение, поэтому компилятору необходимо его получить.