未实现,方法类型错误

时间:2018-08-12 18:30:45

标签: go go-interface

给出以下Go代码:

package main

type CatToy interface {
    Rattle() string
}

type Cat struct {
}

func (cat *Cat) Play(catToy CatToy) {
    println("The cat is playing!", catToy.Rattle())
}

type DogToy interface {
    Roll() string
}

type Dog struct {
}

func (dog *Dog) Play(dogToy DogToy) {
    println("The dog is playing!", dogToy.Roll())
}

type SuperToy struct {
}

func (toy *SuperToy) Rattle() string {
    return "Rattle!!!"
}

func (toy *SuperToy) Roll() string {
    return "Rolling..."
}

type Pet interface {
    Play(toy interface{})
}

func main() {
    cat := &Cat{}
    dog := &Dog{}
    superToy := &SuperToy{}

    // Working
    cat.Play(superToy)
    dog.Play(superToy)

    // Not Working
    pets := []Pet{cat, dog}
    for _, pet := range pets {
        pet.Play(superToy)
    }
}

我遇到这些错误:

# command-line-arguments
./main.go:65:16: cannot use cat (type *Cat) as type Pet in array or slice literal:
    *Cat does not implement Pet (wrong type for Play method)
        have Play(CatToy)
        want Play(interface {})
./main.go:65:21: cannot use dog (type *Dog) as type Pet in array or slice literal:
    *Dog does not implement Pet (wrong type for Play method)
        have Play(DogToy)
        want Play(interface {})

SuperToy同时实现CatToyDogToy。但是,当我使用interface作为参数创建接口Pet时,出现错误。我可以知道如何在里面放一只猫和狗的阵列/切片吗?我想遍历此切片并为每个切片调用一个函数。我还想保留CatToyDogToy接口。我也可以删除Pet界面。

更多信息: 将来,我很有可能会添加更多pets。我认为我不会添加更多操作,例如Play

谢谢

3 个答案:

答案 0 :(得分:3)

我知道您要做什么,但这是不可能的:您的CatDog类型没有实现Pet接口,因为它们的Play方法采用不同的方法类型,因此您将无法仅用Play来调用SuperToy

要解决此问题,您需要创建一个同时具有ToyRoll方法的Rattle接口,并制作Pet.PlayCat.PlayDog.Play将此接口作为参数。

package main

type Cat struct {
}

func (cat *Cat) Play(catToy Toy) {
    println("The cat is playing!", catToy.Rattle())
}

type Dog struct {
}

func (dog *Dog) Play(dogToy Toy) {
    println("The dog is playing!", dogToy.Roll())
}

type Toy interface {
    Roll() string
    Rattle() string
}

type SuperToy struct {
}

func (toy *SuperToy) Rattle() string {
    return "Rattle!!!"
}

func (toy *SuperToy) Roll() string {
    return "Rolling..."
}

type Pet interface {
    Play(toy Toy)
}

func main() {
    cat := &Cat{}
    dog := &Dog{}
    superToy := &SuperToy{}

    // Working
    cat.Play(superToy)
    dog.Play(superToy)

    // Not Working
    pets := []Pet{cat, dog}
    for _, pet := range pets {
        pet.Play(superToy)
    }
}

提供输出

The cat is playing! Rattle!!!
The dog is playing! Rolling...
The cat is playing! Rattle!!!
The dog is playing! Rolling...

答案 1 :(得分:0)

您可以使Play方法采用interface{},然后在方法内部进行类型断言:

func (dog *Dog) Play(toy interface{}) {
    dogToy, isDogToy := toy.(DogToy)
    if !isDogToy {
        println("The dog does not know what to do with this toy!")
        return
    }
    println("The dog is playing!", dogToy.Roll())
}

Go Playground上的完整可执行示例:

https://play.golang.org/p/LZZ-HqpzR-Z

答案 2 :(得分:0)

这是另一个可行的解决方案:

package main

type CatToy interface {
    Rattle() string
}

type Cat struct {
    Toy CatToy
}

func (cat *Cat) Play() {
    println("The cat is playing!", cat.Toy.Rattle())
}

type DogToy interface {
    Roll() string
}

type Dog struct {
    Toy DogToy
}

func (dog *Dog) Play() {
    println("The dog is playing!", dog.Toy.Roll())
}

type SuperToy struct {
}

func (toy *SuperToy) Rattle() string {
    return "Rattle!!!"
}

func (toy *SuperToy) Roll() string {
    return "Rolling..."
}

type Pet interface {
    Play()
}

func main() {
    superToy := &SuperToy{}
    cat := &Cat{superToy}
    dog := &Dog{superToy}

    // Working
    cat.Play()
    dog.Play()

    // Working also
    pets := []Pet{cat, dog}
    for _, pet := range pets {
        pet.Play()
    }
}

此解决方案使Cat + CatToyDog + DogToymain + SuperToy独立。这样可以提取单独的程序包。

但是,我确实同意@Volker和@Ullaakut。对于Go来说,这种解决方案似乎不是惯用的。我仍然不确定合适的解决方案。