在这个程序中,我保存对返回切片中特定实现的函数的引用。
在SpeakAll中我会调用每个函数来获取它的相应对象并在其上调用Speak。
问题:无法遍历数组并获得输出
package main
import "fmt"
type IAnimal interface {
Speak() string
}
type Cat struct {}
func (c Cat) Speak() string {
return "meow!"
}
type Dog struct {}
func (d Dog) Speak() string {
return "woof!"
}
type Zoo struct {
Animals []func() IAnimal
}
func (zoo Zoo) AddAnimal(animal func() IAnimal) {
if zoo.Animals == nil {
zoo.Animals = make([]func() IAnimal, 0)
}
zoo.Animals = append(zoo.Animals, animal)
}
func (zoo Zoo) SpeakAll() {
for _, animal := range zoo.Animals {
fmt.Println(animal().Speak())
}
}
func main() {
catFunc := func() IAnimal {return Cat{}}
dogFunc := func() IAnimal {return Dog{}}
z := Zoo{}
z.AddAnimal(catFunc)
z.AddAnimal(dogFunc)
z.SpeakAll()
}
答案 0 :(得分:0)
您的问题是AddAnimal已被定义为Zoo类型的方法接收器,而不是* Zoo类型。这意味着当您调用z.AddAnimal(catFunc)时,您将Zoo的副本(包括切片Animals)传递给该方法,然后将该函数附加到原始Zoo的副本,但是不是原来的动物园。
将方法更改为这样的指针接收器,它将接收指向原始结构的指针:
func (zoo *Zoo) AddAnimal(animal func() IAnimal) {
需要考虑的其他一些事项:
1 - 您不需要以下代码 - 如果它没有,则追加将创建切片:
if zoo.Animals == nil {
zoo.Animals = make([]func() IAnimal, 0)
}
2 - 在Go中,你通常不会使用I作为界面的名字前缀。
3 - 如果你真的有一个带有单个切片的Zoo,你可以改为将方法添加到自定义切片类型:
type Zoo []func() IAnimal
func (zoo *Zoo) AddAnimal(animal func() IAnimal) {
*zoo = append(*zoo, animal)
}
func (zoo Zoo) SpeakAll() {
for _, animal := range zoo {
fmt.Println(animal().Speak())
}
}
func main() {
catFunc := func() IAnimal {return Cat{}}
dogFunc := func() IAnimal {return Dog{}}
var z Zoo
z.AddAnimal(catFunc)
z.AddAnimal(dogFunc)
z.SpeakAll()
}