遍历结构体集合(切片)的通用方法

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

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泛型...总有一天)。它最大的优点是不需要向FooBar或任何未来可能需要使用的类型添加新方法。

英文:

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.

huangapple
  • 本文由 发表于 2014年2月25日 20:42:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/22014552.html
匿名

发表评论

匿名网友

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

确定