保存对切片中func的引用

时间:2017-03-09 23:56:42

标签: go

在这个程序中,我保存对返回切片中特定实现的函数的引用。

在SpeakAll中我会调用每个函数来获取它的相应对象并在其上调用Speak。

问题:无法遍历数组并获得输出

Go Playground

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()
}

1 个答案:

答案 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()
}