给出以下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
同时实现CatToy
和DogToy
。但是,当我使用interface作为参数创建接口Pet
时,出现错误。我可以知道如何在里面放一只猫和狗的阵列/切片吗?我想遍历此切片并为每个切片调用一个函数。我还想保留CatToy
和DogToy
接口。我也可以删除Pet
界面。
更多信息:
将来,我很有可能会添加更多pets
。我认为我不会添加更多操作,例如Play
。
谢谢
答案 0 :(得分:3)
我知道您要做什么,但这是不可能的:您的Cat
和Dog
类型没有实现Pet
接口,因为它们的Play
方法采用不同的方法类型,因此您将无法仅用Play
来调用SuperToy
。
要解决此问题,您需要创建一个同时具有Toy
和Roll
方法的Rattle
接口,并制作Pet.Play
,Cat.Play
和Dog.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上的完整可执行示例:
答案 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 + CatToy
和Dog + DogToy
与main + SuperToy
独立。这样可以提取单独的程序包。
但是,我确实同意@Volker和@Ullaakut。对于Go来说,这种解决方案似乎不是惯用的。我仍然不确定合适的解决方案。