0

给定以下 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。_ 但是,当我创建一个Pet以 interface 作为参数的接口时,我得到一个错误。我可以知道我怎样才能得到一个里面有猫和狗的数组/切片吗?我想遍历这个切片并为每个切片调用一个函数。我也想保留CatToyDogToy接口。我也可以删除Pet接口。

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

谢谢

4

3 回答 3

3

我明白你想要做什么,但这是不可能的:你的CatDog类型不实现Pet接口,因为它们的Play方法采用不同的类型,所以你不能只Play用你的SuperToy.

要解决此问题,您需要创建一个Toy同时具有 theRoll和方法的接口,Rattle并 make并将此接口作为参数。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...
于 2018-08-12T18:59:08.927 回答
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

于 2018-08-12T20:26:55.800 回答
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 + DogToy独立于main + SuperToy. 这允许提取以分离包。

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

于 2018-08-12T22:19:38.550 回答