英文:
Generic method to iterate over collection (slice) of structs
问题
在Go语言中,你想要创建一个函数getIds([]Idable),它可以接受任何实现了GetId()方法的结构体。有没有一种巧妙的方法可以实现这个功能呢?以下是你的代码的翻译:
type Foo struct { Id int }
type Bar struct { Id int }
func getIdsFoo(foos []Foo) {
  ids := make([]int, len(foos))
  // 迭代并将所有的id存入ids数组中
}
func getIdsBar(bars []Bar) {
  ids := make([]int, len(bars))
  // 迭代并将所有的id存入ids数组中
}
你想要创建一个通用的函数getIds([]Idable),可以接受任何实现了GetId()方法的结构体。
英文:
I have following code in Go:
type Foo struct { Id int }
type Bar struct { Id int }
func getIdsFoo(foos []Foo) {
  ids = make([]int, len(foos))
  // iterate and get all ids to ids array
}
func getIdsBar(bars []Bar) {
  ids = make([]int, len(bars))
  // iterate and get all ids to ids array
}
Is there a clever way to create a function getIds([]Idable) that can take any struct that have method GetId() implemented?
答案1
得分: 3
type Identifiable interface {
GetId() int
}
func GatherIds(ys []Identifiable) []int {
xs := make([]int, 0, len(ys))
for _, i := range ys {
xs = append(xs, i.GetId())
}
return xs
}
英文:
type Identifiable interface {
    GetId() int
}
func GatherIds(ys []Identifiable) []int {
    xs := make([]int, 0, len(ys))
    for _, i := range ys {
        xs = append(xs, i.GetId())
    }
    return xs
}
答案2
得分: 2
sort使用了一种设计模式,可能对你有所帮助。
创建一个在_slice-like_接口上工作的函数。然后基于具体类型的切片创建新类型。
希望代码比我的描述更清晰。http://play.golang.org/p/TL6yxZZUWT
type IdGetter interface {
	GetId(i int) int
	Len() int
}
func GetIds(ig IdGetter) []int {
	ids := make([]int, ig.Len())
	for i := range ids {
		ids[i] = ig.GetId(i)
	}
	return ids
}
type Foo struct{ Id int }
type Bar struct{ Id int }
type FooIdGetter []Foo
func (f FooIdGetter) GetId(i int) int {
	return f[i].Id
}
func (f FooIdGetter) Len() int {
	return len(f)
}
type BarIdGetter []Bar
func (b BarIdGetter) GetId(i int) int {
	return b[i].Id
}
func (b BarIdGetter) Len() int {
	return len(b)
}
func main() {
	var f = []Foo{{5}, {6}, {7}}
	var b = []Bar{{10}, {11}, {12}}
	fmt.Println("foo ids:", GetIds(FooIdGetter(f)))
	fmt.Println("bar ids:", GetIds(BarIdGetter(b)))
}
仍然有一些比较繁琐的样板代码(Go泛型...总有一天)。它最大的优点是不需要向Foo、Bar或任何未来可能需要使用的类型添加新方法。
英文:
sort uses a design patter that might help you.
Create a function that works on an slice-like interface. Then create new types based off of a slice of your concrete types.
Hopefully, the code is more clear than my description. http://play.golang.org/p/TL6yxZZUWT
type IdGetter interface {
	GetId(i int) int
	Len() int
}
func GetIds(ig IdGetter) []int {
	ids := make([]int, ig.Len())
	for i := range ids {
		ids[i] = ig.GetId(i)
	}
	return ids
}
type Foo struct{ Id int }
type Bar struct{ Id int }
type FooIdGetter []Foo
func (f FooIdGetter) GetId(i int) int {
	return f[i].Id
}
func (f FooIdGetter) Len() int {
	return len(f)
}
type BarIdGetter []Bar
func (b BarIdGetter) GetId(i int) int {
	return b[i].Id
}
func (b BarIdGetter) Len() int {
	return len(b)
}
func main() {
	var f = []Foo{{5}, {6}, {7}}
	var b = []Bar{{10}, {11}, {12}}
	fmt.Println("foo ids:", GetIds(FooIdGetter(f)))
	fmt.Println("bar ids:", GetIds(BarIdGetter(b)))
}
There is still a bit more boilerplate than is pleasant, (Go generics... someday). It's greatest advantage is that new methods do not need to be added to Foo, Bar, or any future type you may need to work with.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论