Указатели и интерфейсы в Go - PullRequest
0 голосов
/ 19 декабря 2018

Я пытаюсь понять, что я делаю не так здесь .. все ответы приветствуются:)

Если раскомментирование "// grow ()" работает,

, иначе ошибки:

prog.go: 38: 2: случай переключения невозможного типа: p (тип plant) не может иметь динамический тип plant1 (метод выращивания имеет приемник указателя) prog.go: 39: 16: утверждение невозможного типа:plant1 не реализует plant (метод выращивания имеет приемник указателя) prog.go: 40: 2: регистр переключения невозможного типа: p (тип plant) не может иметь динамический тип plant2 (метод выращивания имеет приемник указателя) prog.go: 41: 16:невозможное утверждение типа: plant2 не реализует plant (метод выращивания имеет приемник указателя) prog.go: 60: 12: нельзя использовать p1 (тип plant1) в качестве типа plant в аргументе для showHeight: plant1 не реализует plant (метод выращивания имеет приемник указателя)) prog.go: 61: 12: нельзя использовать p2 (тип plant2) в качестве типа plant в аргументе для showHeight: plant2 не реализует plant (метод выращивания имеет приемник указателя)

https://play.golang.org/p/oMv7LdW85yK

package main

import (
    "fmt"
)

type plant1 struct {
    name   string
    height int
}

type plant2 struct {
    species string
    height  int
}

func (self *plant1) grow() {
    self.height++
}
func (self *plant2) grow() {
    self.height++
}

func (self plant1) getHeight() int {
    return self.height
}
func (self plant2) getHeight() int {
    return self.height
}

type plant interface {
    getHeight() int
    //grow()
}

func showHeight(p plant) {
    switch p.(type) {
    case plant1:
        fmt.Println(p.(plant1).name, `Height = `, p.(plant1).getHeight())
    case plant2:
        fmt.Println(p.(plant2).species, `Height = `, p.(plant2).getHeight())
    }

}

func main() {

    p1 := plant1{
        name:   `Plant 10`,
        height: 1,
    }
    p2 := plant2{
        species:   `Plant 20`,
        height: 1,
    }
    p1.grow()
    p1.grow()
    p2.grow()   

    showHeight(p1)
    showHeight(p2)
}

Ответы [ 3 ]

0 голосов
/ 19 декабря 2018

Ваша функция func showHeight(p plant) принимает интерфейс в качестве параметра, и интерфейс принимает только те типы, которые вы реализуете.

С комментариями к регистру //grow()

Поскольку вы прокомментировали grow() plant имеет только один метод getHeight(), который вы реализовали для plant 1 и plant 2, и все идет гладко.

Случай без комментариев grow()

Теперь ни один из ваших типов (plant1или установка 2) реализовать интерфейс plant, поскольку grow() был определен для *plant1, а *plant2 не для plant1 и plant2.Результат;Ваша функция showHeight(p plant), которая принимает интерфейс типа установки, не может принять pl, p2, поскольку они больше не относятся к типу plant.

Исправление:

Передача указателей для работы в качествеshowHeight(&p1) и showHeight(&p2), а в случаях определения функции и операторах печати заменить plant1 и plant2 на *plant1 и *plant2

Может возникнуть путаница: getHeight не былореализовано в *plant1 и *plant2, почему *plant1 и *plant2 имеют тип plant?Логика: когда вы передаете указатели, значения могут быть получены из них, чтобы вызвать getHeight, но когда вы передаете значения, не может быть получен адрес для вызова grow()

SIDENOTE: p.(*plant2).getHeight() может бытьизменено на p.getHeight(), поскольку p является интерфейсом и может вызывать свои собственные методы.

0 голосов
/ 19 декабря 2018

Это связано с тем, как работает набор методов в Go.В Go метод для конкретного типа получателя реализует как тип значения, так и тип указателя, тогда как метод для типа получателя указателя реализует только значение указателя.

В случае метода grow методуказатель типа приемника *plant1/*plant2 используется, поэтому только значение указателя этих типов может реализовать метод grow на интерфейсе, а конкретный тип значения не может.

Поскольку тип приемника на getHeightМетод является конкретным типом получателя, он реализует как значение типа указателя (*plant1/*plant2), так и значение типа как plant & plant2.

Если вы измените параметр (p), переданный на showHeight на *plant1/*plant2 тип и измените утверждение типа на ожидаемое *plant1/*plant2, это решит ошибку.

проверьте этот пример кода игровая ссылка

0 голосов
/ 19 декабря 2018

Значение, которое вы переносите в интерфейс, не адресуется.Значение должно быть адресуемым для вызова методов на указателях получателей.Методы grow объявлены с указателем приемника.Таким образом, компилятор видит, что интерфейс plant не реализуется ни типом plant1, ни типом plant2.Таким образом, вы не можете передать plant1 или plant2 как plant в showHeight func.И переключение невозможно, потому что реализации интерфейса plant не включают типы plant1 и plant2.

См. Почему значение, хранимое в интерфейсе, не адресуется в Golang

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