在Golang中,可以使用反射(reflect)以一种通用的方式迭代(slice)切片吗?

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

Golang: Is there a way to iterate over a slice in a generic way using reflect?

问题

有没有一种使用反射以通用方式迭代切片的方法?

type LotsOfSlices struct {
	As []A
	Bs []B
	Cs []C
	//.... 还有很多这样的切片
}

type A struct {
	F string
	//.... 和其他结构体不同的很多其他属性
}

type B struct {
	F string
	//.... 和其他结构体不同的很多其他属性
}

type C struct {
	F string
	//.... 和其他结构体不同的很多其他属性
}

我想使用反射来减少代码复杂性和重复代码。这种做法可行吗?这是一个不好的主意吗?

例如,不是这样写:

func processData(l LotsOfSlice){
	for _, a := range l.As{
		// 使用 a.F
	}
	for _, b := range l.Bs{
		// 使用 b.F
	}
	for _, c := range l.Cs{
		// 使用 c.F
	}
	...
}

而是像这样写:

func processData(l LotsOfSlices){
	t := reflect.TypeOf(l)
	for i := 0; i < t.NumField(); i++ {
		zs := reflect.ValueOf(l).Field(i).Interface()
		for _, z := range zs{
			// 使用 z.F
		}
	}
}
英文:

Is there a way to iterate over a slice in a generic way using reflection?

type LotsOfSlices struct {
	As []A
	Bs []B
	Cs []C
	//.... and lots more of these
}

type A struct {
	F string
	//.... and lots of other stufff that&#39;s different from the other structs
}

type B struct {
	F string
	//.... and lots of other stufff that&#39;s different from the other structs
}

type C struct {
	F string
	//.... and lots of other stufff that&#39;s different from the other structs
}

I want to use reflection to reduce code complexity and duplicate code. Is this possible? Is this a bad idea?

For example, not this:

func processData(l LotsOfSlice){
	for _, a := range l.As{
		// use a.F
	}
	for _, b := range l.Bs{
		// use b.F
	}
	for _, c := range l.Cs{
		// use c.F
	}
	...
}

But something like this instead:

func processData(l LotsOfSlices){
	t := reflect.TypeOf(l)
	for i := 0; i &lt; t.NumField(); i++ {
		zs := reflect.ValueOf(l).Field(i).Interface()
		for _, z := range zs{
			// use z.F
		}
	}
}

答案1

得分: 2

使用Value.LenValue.Index来迭代数组或切片:

func processData(l LotsOfSlices) {
    v := reflect.ValueOf(l)
    for i := 0; i < v.NumField(); i++ {
        f := v.Field(i)
        if f.Kind() != reflect.Slice {
            continue
        }
        for i := 0; i < f.Len(); i++ {
            e := f.Index(i)
            s := e.FieldByName("F")
            // 对 s 进行操作
        }
    }
}

请注意,这是一段Go语言代码,用于处理包含多个切片的结构体。在代码中,使用reflect包中的Value.LenValue.Index函数来获取切片的长度和索引元素。然后,可以使用FieldByName函数来获取结构体字段的值。你可以在代码中的注释部分添加对s变量的操作。

英文:

Use Value.Len and Value.Index to iterate over an array or slice:

func processData(l LotsOfSlices) {
	v := reflect.ValueOf(l)
	for i := 0; i &lt; v.NumField(); i++ {
		f := v.Field(i)
		if f.Kind() != reflect.Slice {
			continue
		}
		for i := 0; i &lt; f.Len(); i++ {
			e := f.Index(i)
            s := e.FieldByName(&quot;F&quot;)
			// Do something with s
		}
	}
}

答案2

得分: 0

如果你的结构体产生类似的结果(返回int或操作字符串),但每个结构体类型的操作方式是独特的,你可以在它们上定义函数:

func (a *A) GetResult() int { // 求两个数的和
    return a.p1 + a.p2
}

func (b *B) GetResult() int { // 求两个数的差
    return b.p1 - b.p2
}

func (c *C) GetResult() int { // 求两个数的积
    return c.p1 * c.p2
}

然后定义一个接口Operable

type Operable interface {
    GetResult() int // 共享的函数
}

接下来,编写一个函数,该函数接受该接口作为参数,任何实现该接口中所有函数的结构体都可以作为参数传入:

func processOperable(o []Operable) {
    for _, v := range o {
        v.GetResult() // 对于每个结构体都是独特的操作
    }
}
英文:

if your structs do similar end result (returns int or operates on strings) but does so uniquely for each struct type you can define functions on them:

func (a *A) GetResult() int { // sums two numbers
    return a.p1 + a.p2
}

func (b *B) GetResult() int { // subtracts two numbers
    return b.p1 - b.p2
}

func (c *C) GetResult() int { // times two numbers
    return c.p1 * c.p2
}

then define an interface Operable

type Operable interface {
    GetResult() int // shared function
}

then make a function that accepts the interface as argument, and any struct that implements all functions in that interface can be accepted into it as an argument

func processOperable(o []Operable){
    for _, v := range o{
        v.GetResult() --&gt; unique for each struct
    }
}

huangapple
  • 本文由 发表于 2022年10月5日 01:31:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/73951585.html
匿名

发表评论

匿名网友

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

确定