Подтвердить что ты не робот

Почему интерфейс не может быть реализован с помощью указателей-указателей

Я смущен, почему это невозможно скомпилировать с помощью:

невозможное утверждение типа:        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`
}
4b9b3361

Ответ 1

Потому что он *Faz не Faz.

func main() {
    foo := New().(*Faz)
    log.Println(foo)
}

Ответ 2

Я думаю, что ответ на этот вопрос должен иметь более ретроспективный подход к грамматике и как реализовать его с помощью разработки программного обеспечения. (Извините за упрощение)


Сначала быстро вспомните, что такое 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 будет квалифицироваться как тип интерфейса в коде? Выберите, кто удовлетворяет вашему контракту, и только этот тип может ввести тип интерфейса в ваш код.