如何将不同的结构体放入列表中并进行操作?

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

How to put various structs in a list and manipulate?

问题

我想以编程的方式操作具有相同名称和类型的各种结构体字段,就像下面的示例一样,但我不知道如何将不同的结构体放入一个列表中。

package main

import "fmt"

type A struct {
    Cnt int
}

type B struct {
    Cnt int
}

func main() {
    a := &A{}
    b := &B{}
    list := []something{
        a,
        b,
    }
    for _, item := range list {
        item.Cnt++
    }
    fmt.Printf("a.Cnt: %d, b.Cnt: %d", a.Cnt, b.Cnt)
}
英文:

I want to manipulate various structs' field which has same name and type programmatically like the following but I have no idea how to put varied structs in a list.

package main

import "fmt"

type A struct {
	Cnt int
}

type B struct {
	Cnt int
}

func main() {
	a := &A{}
	b := &B{}
	list := []something{
		a,
		b,
	}
	for _, item := range list {
		item.Cnt++
	}
	fmt.Printf("a.Cnt: %d, b.Cnt: %d", a.Cnt, b.Cnt)
}

答案1

得分: 3

为类型声明一个通用接口。方法应该反映你想要在值上执行的任何操作。这里我使用add作为增量的概括。

type Cntr interface {
    Add(i int)
}

在每个类型上实现该接口:

func (a *A) Add(i int) { a.Cnt += i }
func (b *B) Add(i int) { b.Cnt += i }

声明一个接口类型的切片,并使用类型A和B的值:

a := &A{}
b := &B{}
list := []Cntr{ // <-- 接口类型的切片
    a,
    b,
}

增加计数器:

for _, item := range list {
    item.Add(1)
}

打印结果:

fmt.Printf("a.Cnt: %d, b.Cnt: %d", a.Cnt, b.Cnt)
// 输出 a.Cnt: 1, b.Cnt: 1

在此程序上运行此 playground

英文:

Declare a common interface for the types. The methods should reflect whatever action you want to executed on the values. I use add here as generalization of increment.

type Cntr interface {
	Add(i int)
}

Implement that interface on each type:

func (a *A) Add(i int) { a.Cnt += i }
func (b *B) Add(i int) { b.Cnt += i }

Declare slice of interface type and with values of types *A and *B:

a := &amp;A{}
b := &amp;B{}
list := []Cntr{ // &lt;-- slice of the interface type
	a,
	b,
}

Increment the counters:

for _, item := range list {
	item.Add(1)
}

Print the results:

fmt.Printf(&quot;a.Cnt: %d, b.Cnt: %d&quot;, a.Cnt, b.Cnt)
// prints a.Cnt: 1, b.Cnt: 1

Run this playground on the program.

答案2

得分: 1

使用反射API来获取任意结构类型中命名字段的指针:

func getFieldPtr(v interface{}, name string) interface{} {
	return reflect.ValueOf(v).Elem().FieldByName(name).Addr().Interface()
}

使用方法如下:

a := &A{}
b := &B{}
list := []interface{}{
	a,
	b,
}
for _, item := range list {
	pcnt := getFieldPtr(item, "Cnt").(*int)
	*pcnt++
}
fmt.Printf("a.Cnt: %d, b.Cnt: %d", a.Cnt, b.Cnt)

你可以在这里查看代码示例:https://go.dev/play/p/InVlnv37yqW

英文:

Use the reflect API to get a pointer to a named field in an arbitrary struct type:

func getFieldPtr(v interface{}, name string) interface{} {
	return reflect.ValueOf(v).Elem().FieldByName(name).Addr().Interface()
}

Use it like this:

a := &amp;A{}
b := &amp;B{}
list := []interface{}{
	a,
	b,
}
for _, item := range list {
	pcnt := getFieldPtr(item, &quot;Cnt&quot;).(*int)
	*pcnt++
}
fmt.Printf(&quot;a.Cnt: %d, b.Cnt: %d&quot;, a.Cnt, b.Cnt)

https://go.dev/play/p/InVlnv37yqW

huangapple
  • 本文由 发表于 2021年11月27日 12:03:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/70131963.html
匿名

发表评论

匿名网友

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

确定