泛型:处理具有相同数据成员类型的不同结构类型

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

go generics: processing different struct types with same data member types

问题

有两种结构类型,FooBar,都有一个int类型的数据成员val。我正在尝试编写一个通用函数,可以处理这两种类型。我尝试了以下代码,但不起作用。

package main

import "fmt"

type Foo struct {
	val int
}

type Bar struct {
	val int
}

func Add[T any](slice []T) int {
	var sum int
	for _, elem := range slice {
		sum += elem.val
	}
	return sum
}

func Test() {
	f1 := Foo{val: 2}
	f2 := Foo{val: 2}
	fslice := []Foo{f1, f2}
	fsum := Add(fslice)
	fmt.Printf("fsum = %d\n", fsum)

	b1 := Bar{val: 3}
	b2 := Bar{val: 3}
	bslice := []Bar{b1, b2}
	bsum := Add(bslice)
	fmt.Printf("bsum = %d\n", bsum)
}

func main() {
	Test()
}

编译器报错如下。

$ go run generics1.go
# command-line-arguments
./generics1.go:16:15: elem.val undefined (type T has no field or method val)

Go Playground链接:https://go.dev/play/p/mdOMH3xuwu7

有什么可能的方法来解决这个问题?

英文:

There are two struct types, Foo and Bar, with an int data member val. I am trying to write a generic function that can handle both types. I tried the following and this did not work.

package main

import "fmt"

type Foo struct {
	val int
}

type Bar struct {
	val int
}

func Add[T any](slice []T) int {
	var sum int
	for _, elem := range slice {
		sum += elem.val
	}
	return sum
}

func Test() {
	f1 := Foo{val: 2}
	f2 := Foo{val: 2}
	fslice := []Foo{f1, f2}
	fsum := Add(fslice)
	fmt.Printf("fsum = %d\n", fsum)

	b1 := Bar{val: 3}
	b2 := Bar{val: 3}
	bslice := []Bar{b1, b2}
	bsum := Add(bslice)
	fmt.Printf("bsum = %d\n", bsum)
}

func main() {
	Test()
}

The compiler throws the following error.

$ go run generics1.go
# command-line-arguments
./generics1.go:16:15: elem.val undefined (type T has no field or method val)

Go playground link: https://go.dev/play/p/mdOMH3xuwu7

What could be a possible way to approach this?

答案1

得分: 2

根据golang 1.18发布说明

Go编译器不支持访问类型参数类型的结构字段x.f,即使类型参数的类型集中的所有类型都有字段f。我们可能会在将来的版本中删除此限制。

你可以定义一个GetVal()接口方法来获取val,并将此方法作为泛型的类型约束的一部分。

示例代码:

type Foo struct {
	val int
}

func (f Foo) GetVal() int {
	return f.val
}

type Bar struct {
	val int
}

func (b Bar) GetVal() int {
	return b.val
}

type MyType interface {
	Foo | Bar
	GetVal() int
}

func Add[T MyType](slice []T) int {
	var sum int
	for _, elem := range slice {
		sum += elem.GetVal()
	}
	return sum
}

https://go.dev/play/p/0eJZpqy7q8f

英文:

Per golang 1.18 release note

> The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type parameter's type set have a field f. We may remove this restriction in a future release.

You could define one GetVal() interface method to retrieve the val, and use this method as part of type constraint of generic.

Sample codes

type Foo struct {
	val int
}

func (f Foo) GetVal() int {
	return f.val
}

type Bar struct {
	val int
}

func (b Bar) GetVal() int {
	return b.val
}

type MyType interface {
	Foo | Bar
	GetVal() int
}

func Add[T MyType](slice []T) int {
	var sum int
	for _, elem := range slice {
		sum += elem.GetVal()
	}
	return sum
}

https://go.dev/play/p/0eJZpqy7q8f

huangapple
  • 本文由 发表于 2022年11月8日 09:19:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/74354709.html
匿名

发表评论

匿名网友

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

确定