访问传递给可变参数函数的泛型结构体的特定字段

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

Accessing specific field of a generic struct passed to a variadic function

问题

假设我有一个名为foo的通用结构体:

type foo[T any] struct {
	data T
}

我有一个可变参数函数,我想要将一些foo传递给它。它们可以是任何类型的foo。我的理解是,因为foo[int]foo[string]是不同的,所以我需要将省略号定义为any类型,如下所示:

func bar(things ...any) {
	for _, v := range things {
		fmt.Println(v)
	}
}

这确实可以工作。

func main() {
	a := foo[string]{"cheese"}
	b := foo[int]{42}

	bar(a, b)
}

我的问题是,我想要特别访问每个foo中的data字段。但是如果我像这样定义bar函数:

func bar(things ...any) {
	for _, v := range things {
		fmt.Println(v.data)
	}
}

编译器会不可避免地感到不满,因为things可以是任何类型,因此不能保证它们具有data字段。

我知道将始终传递foo,因此我知道将有一个名为data的字段,但是我无法指定我只会传递foo,像这样:

func bar(things ...foo) {
	for _, v := range things {
		fmt.Println(v.data)
	}
}

因为foo的类型没有指定。


如何将未指定数量的foo传递给bar函数,然后访问data字段呢?

英文:

Say I have a generic struct called foo:

type foo[T any] struct {
	data T
}

I have a variadic function that I want to pass some foos to. They could be any type of foo. My understanding is that because a foo[int] is different to a foo[string], I need to define my ellipsis as type any, like so:

func bar(things ...any) {
	for _, v := range things {
		fmt.Println(v)
	}
}

And this indeed works.

func main() {
	a := foo[string]{"cheese"}
	b := foo[int]{42}

	bar(a, b)
}

My problem is that I want to specifically access the data field in each foo. But if I define bar like this,

func bar(things ...any) {
	for _, v := range things {
		fmt.Println(v.data)
	}
}

the compiler gets understandably upset, since things could be anything and, therefore, there is no guarantee they have the field data.

I know there will be a field called data since I'm always passing foos, but I can't specify that I'll only pass foos, like this,

func bar(things ...foo) {
	for _, v := range things {
		fmt.Println(v.data)
	}
}

because the type of foo isn't specified.


How can I pass an unspecified number of foos to bar and then access the data field?

答案1

得分: 1

一种解决方案似乎是使用反射并使用FieldByName访问字段:

func bar(things ...any) {
	for _, v := range things {
		x := reflect.ValueOf(v)
		fmt.Println(x.FieldByName("data"))
	}
}

不过,我不确定这是否会被认为是一个笨拙的解决方案,或者出于某种原因而具有危险性。可能需要在其中进行一些检查,以确保things中的每个元素实际上都是某种类型的foo,否则可能会尝试访问不存在的字段。

英文:

One solution seems to be to use reflection and to access the field using FieldByName:

func bar(things ...any) {
	for _, v := range things {
		x := reflect.ValueOf(v)
		fmt.Println(x.FieldByName("data"))
	}
}

It's not clear to me though if this would be considered a cludge and/or dangerous for some reason or other. Presumably, I'd need some checking in there to ensure that everything in things is actually a foo of some variety or I could be trying to access a field that doesn't exist.

huangapple
  • 本文由 发表于 2022年12月17日 23:14:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/74835196.html
匿名

发表评论

匿名网友

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

确定