将函数的引用保存在切片中。

huangapple go评论88阅读模式
英文:

Saving references to the func's in a slice

问题

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

在SpeakAll函数中,我调用每个函数以获取其对应的对象,并调用其Speak方法。

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

以下是翻译好的代码:

package main

import "fmt"

type IAnimal interface {
	Speak() string
}

type Cat struct {}
func (c Cat) Speak() string {
	return "喵喵!"
}

type Dog struct {}
func (d Dog) Speak() string {
	return "汪汪!"
}

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

你可以在Go Playground上运行这段代码。

英文:

In this program I'm saving references to the functions that are returning specific implementations in a slice.

Within SpeakAll I'm calling each function to get it's corresponding object and calling Speak on it.

Issue: Unable to iterate through array and get an output

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

你的问题是AddAnimal方法被定义为Zoo类型的方法接收器,而不是*Zoo类型。这意味着当你调用z.AddAnimal(catFunc)时,你将一个Zoo的副本(包括切片Animals)传递给该方法,该方法将函数追加到这个副本的原始Zoo中,而不是原始的Zoo。

将该方法改为指针接收器,像这样,它将接收到原始结构体的指针:

func (zoo *Zoo) AddAnimal(animal func() IAnimal) {

还有一些其他需要考虑的事项:

1 - 你不需要以下代码-如果切片为nil,append函数会创建一个切片:

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()
}
英文:

Your problem is that AddAnimal has been defined as a method receiver on the Zoo type, not the *Zoo type. This means that when you call z.AddAnimal(catFunc) you pass a copy of the Zoo (including the slice Animals) to the method, which then appends the function to this copy of the original Zoo, but not the original Zoo.

Change the method to a pointer receiver like this, and it will receive a pointer to the original struct:

func (zoo *Zoo) AddAnimal(animal func() IAnimal) {

Some additional things to consider:

1 - You don't need the following code - append will create the slice if it's nil:

if zoo.Animals == nil {
	zoo.Animals = make([]func() IAnimal, 0)
}

2 - In Go you generally don't prefix names with I for interface.

3 - If you really have a Zoo with a single slice in it, you could instead just add methods to a custom slice type:

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

huangapple
  • 本文由 发表于 2017年3月10日 07:56:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/42707769.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定