Интерфейс не может вызвать метод self - PullRequest
0 голосов
/ 12 октября 2018

Я определил две функции.Когда я передаю указатель на него, я не могу получить определенный метод.Почему это так?

type Visitor interface {
    work()
}

func test(v *Visitor)  {
    v.work() // error
}


func test1(v Visitor)  {
    v.work() // ok
}

Ошибка:

v.work undefined (тип * Посетитель - указатель на интерфейс, а не интерфейс)

любойзнаешь почему, тыс

Ответы [ 2 ]

0 голосов
/ 12 октября 2018
func test(v *Visitor)  {
    v.work() // error
}

v.work() должен быть вызовом метода.Но v имеет тип *Visitor, указатель на интерфейс. Указатель на интерфейс имеет 0 методов, он ничего не реализует (кроме пустого интерфейса interface{}).

При использовании не указателя значение v (или, скорее,его тип) имеет метод work(), так что вы можете вызвать его так:

func test(v Visitor)  {
    v.work() // ok
}

Здесь v.work() работает, потому что v имеет тип Visitor, который является интерфейсом, и содержитметод work().

Что может сбивать с толку, так это то, что если вы добавляете метод к конкретному типу (не указателю, не интерфейсу), соответствующий тип указателя также будет иметь этот метод, и вы можете вызватьтот.Это в Spec: Наборы методов:

Тип может иметь набор методов , связанный с ним.Набор методов типа интерфейса является его интерфейсом.Набор методов любого другого типа T состоит из всех методов , объявленных с типом получателя T. Набор методов соответствующего типа указателя *T - это набор всех методов, объявленных с получателем *T или T (то есть он также содержит набор методов T). Дополнительные правила применяются к структурам, содержащим встроенные поля, как описано в разделе struct types .Любой другой тип имеет пустой набор методов.В наборе методов каждый метод должен иметь уникальное не- пустое имя метода .

Разница в том, что вы пыталисьто же самое с типом интерфейса, который не будет работать.Работает с конкретными (неинтерфейсными) типами.Урок состоит в том, чтобы никогда не использовать указатель на интерфейс, если вы не можете объяснить, почему он нужен (он нужен редко).

0 голосов
/ 12 октября 2018

Как ясно указывает на ошибку:

v.work undefined (тип * Посетитель - указатель на интерфейс, а не интерфейс)

Это потому, что work ()функция вызывается по указателю на получателя, но определяется значением.

type Visitor interface {
    work()
}

Но вы передаете получатель типа указателя во втором случае, в котором вы получаете ошибку.

В спецификации Голанга Наборы методов определяются как:

Тип может иметь набор методов, связанный с ним.Набор методов типа интерфейса является его интерфейсом.Набор методов любого другого типа T состоит из всех методов, объявленных с типом получателя T. Набор методов соответствующего типа указателя * T является набором всех методов, объявленных с получателем * T или T (то есть он также содержит методнабор T).Дополнительные правила применяются к структурам, содержащим встроенные поля, как описано в разделе о типах структур.Любой другой тип имеет пустой набор методов.В наборе методов каждый метод должен иметь уникальное непустое имя метода.

Один из подходов, который вы можете сделать, - реализовать интерфейс с помощью структуры, для которой вы можете вызвать метод work ().

package main

import "fmt"

type Visitor struct{}

type Visit interface {
    work()
}

func test(v Visit)  {
    v.work() // error
    fmt.Printf("%+v", v)
}

func (v *Visitor) work(){}


func main(){
       v := Visitor{}
       test(&v)
}

Рабочий код на Игровая площадка Go

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...