go - 在 go (1.18) 中对泛型进行多态实现的最佳方法是什么?

标签 go generics

我想创建一个 Vector 类型,它在其内部数据上是通用的,但在给定输入类型的方法实现方式上可能有所不同。

type SupportedType interface {
         ~int64 | ~uint64 |  ~float64 | string | bool | time.Time
}

type Vec[T SupportedType] struct {
    data []T
}

我想根据类型在函数上添加不同的实现。例如:

func (vec Vec[T]) Sort() {
    ...
}

在大多数泛型类型中 <会工作得很好。但是,如果 T -> time.Time我想使用 Before方法和如果 T --> bool然后我希望所有错误值都在真实值之前。

我对如何实现这一点有一些想法,但在新的泛型世界中,什么会被认为是“惯用的”?我的应用程序对性能敏感。


对所有具有相同功能的类型使用类型联合是行不通的 (https://play.golang.com/p/QWE-XteWpjL)。

在特定类型的结构中嵌入容器确实有效(https://play.golang.com/p/j0AR48Mto-a)但需要使用接口(interface),这意味着 LessVal在示例函数中不能内联。如果类型联合中的子集之间没有清晰的描述,它也可能无法很好地工作。

最佳答案

顺便说一句,已经有一个用于排序的库

https://pkg.go.dev/golang.org/x/exp/slices#Sort

1。您可以使用泛型创建接口(interface),然后为其键入断言。

例子:

type Lesser[T SupportedType] interface {
    Less(T) bool
}

type Vec[T SupportedType] []T

func (vec Vec[T]) Less(a, b int) bool {
    return any(vec[a]).(Lesser[T]).Less(vec[b])
}

func main() {
    vs := Vec[String]([]String{"a", "b", "c", "d", "e"})
    vb := Vec[Bool]([]Bool{false, true})
    fmt.Println(vs.Less(3, 1))
    fmt.Println(vb.Less(0, 1))
}

playground 1

2。您可以将类型保存在 Vec 上。

例子:

type Lesser[T SupportedType] interface {
    Less(T) bool
}

type Vec[T SupportedType, L Lesser[T]] []T

func (vec Vec[T, L]) Less(a, b int) bool {
    return any(vec[a]).(L).Less(vec[b])
}

func main() {
    vs := Vec[String, String]([]String{"a", "b", "c", "d", "e"})
    fmt.Println(vs.Less(3, 1))
}

playground 2

3。嵌套类型约束

感谢@blackgreen

例子:

type SupportedType interface {
    Int8 | Time | Bool | String
}

type Lesser[T SupportedType] interface {
    Less(T) bool
}

type Vec[T interface {
    SupportedType
    Lesser[T]
}] []T

func (vec Vec[T]) Less(a, b int) bool {
    return vec[a].Less(vec[b])
}

func main() {
    vs := Vec[String]([]String{"a", "b", "c", "d", "e"})
    fmt.Println(vs.Less(3, 1))
}

playgrond 3

基准:

benchmark 1 : 28093368          36.52 ns/op       16 B/op          1 allocs/op

benchmark 2 : 164784321          7.231 ns/op           0 B/op          0 allocs/op

benchmark 3 : 212480662          5.733 ns/op           0 B/op          0 allocs/op

Embedding a container inside type specific structs:
benchmark 4 : 211429621          5.720 ns/op           0 B/op          0 allocs/op

哪一个最适合您,完全取决于您。但 IMO 3 号是最好的。

关于go - 在 go (1.18) 中对泛型进行多态实现的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71542373/

相关文章:

java - 如何将接口(interface)中的 Java 泛型类型参数限制为某些类

java - 泛型 - 从 Class<T> 获取值

Java GUI通过组合框改变颜色,使用集合和对象数组

Swift - MyClass 与 NSManagedObject 不同

GoLang - 如何执行/生成进程 'Hidden'

go - 如果没有进一步的语句要执行,为什么 time.Sleep 不起作用?

arrays - 如何从go lang中的json数组访问键和值

go - 为这个用例构建 go 项目

java调用通用静态方法

docker - Go 可执行文件是如何在 Docker 中创建的?