Ответ 1
Потому что он *Faz
не Faz
.
func main() {
foo := New().(*Faz)
log.Println(foo)
}
Я смущен, почему это невозможно скомпилировать с помощью:
невозможное утверждение типа: Faz не реализует Foo (метод Bar имеет приемник указателей)
Если я сделаю приемник для Faz.Bar значением Faz, а не указателем Faz, тогда он компилируется отлично, но я думал, что всегда лучше иметь приемники указателей, чтобы значения не копировались вокруг?
package main
import (
"log"
)
func main() {
foo := New().(Faz)
log.Println(foo)
}
type Foo interface {
Bar() string
}
func New() Foo {
return &Faz{}
}
type Faz struct {
}
func (f *Faz) Bar() string {
return `Bar`
}
Потому что он *Faz
не Faz
.
func main() {
foo := New().(*Faz)
log.Println(foo)
}
Я думаю, что ответ на этот вопрос должен иметь более ретроспективный подход к грамматике и как реализовать его с помощью разработки программного обеспечения. (Извините за упрощение)
Сначала быстро вспомните, что такое types
?
Это всего лишь блоки памяти с логикой компилятора сверху. Что отличает array
от string
то, что компилятор позволяет нам делать с этими блоками памяти. (Подумайте глубже, и вы можете начать понимать истинную разницу между языками strongly typed
и dynamically typed
.)
Теперь вам нужно понять, что указатели являются их собственными типами для каждого. *variable
- это другой блок памяти (aka type), чем variable
. Это просто, что компилятор всегда предполагает, что содержимое *variable
всегда будет адресом в блок памяти типа справа от объявления вместе с другими ограничениями/функциями, которые он налагает.
Затем давайте вспомним, что такое интерфейс.
Псевдо-научное определение: набор требований для любого гражданина первого класса, относящегося к определенному типу.
Перевод на программное обеспечение - любой блок памяти (типы), который имеет одинаковую структуру памяти (вспомните упаковка структуры), связанный с ним, как описано в контракте (interface
) можно передавать так же, как и имя типа, о котором упоминается в контракте.
Теперь вы можете начать понимать, что когда вы говорите
func (f *Faz) Bar() string
является f
блоком памяти, содержащим функцию, где f
type является указателем на Faz
где области
func (f Faz) Bar() string
является f
блоком памяти, где f
type Faz
Итак, когда вы говорите, что переменная типа *Faz
удовлетворяет контракту, то как вы можете предположить, что переменная типа Faz
будет квалифицироваться как тип интерфейса в коде? Выберите, кто удовлетворяет вашему контракту, и только этот тип может ввести тип интерфейса в ваш код.