如何为可以使用 len() 的东西编写 Go 类型约束?

kam*_*rup 4 generics types go

我正在尝试为 Go 程序编写一个类型约束,它接受“任何你可以接受 len() 的东西”。但我真的无法弄清楚。

我想要这样的东西:

LenOf[m Measurable](m M) int {
    return len(m)
}
Run Code Online (Sandbox Code Playgroud)

我尝试了一些事情。外汇。这个天真的东西可以编译,但不适用于所有类型(例如 fx []User):

type Measurable interface {
    ~string | []any | ~map[any]any
}
Run Code Online (Sandbox Code Playgroud)

然后继续类似下面的内容,这不仅使函数签名LenOf()极其笨拙,而且在调用站点上编写起来也很笨拙(并且仍然无法编译)

type Measurable[K comparable, V any] interface {
   ~string | []V | ~map[K]V
}
Run Code Online (Sandbox Code Playgroud)

bla*_*een 8

为什么?内置len已经是“通用的”。

\n
\n

话虽如此,让我们看看为什么定义这样的约束是一个坏主意。Go 规范有一段 \xe2\x80\x94 Length andcapacity,可以帮助:

\n
\n

如果参数类型是类型参数 P,则调用len(e)(或cap(e)分别)必须对于 P 的类型集中的每个类型有效。结果是参数的长度(或容量),该参数的类型对应于实例化 P 的类型参数。

\n
\n

为“可测量”类型编写包罗万象的约束的问题是:

\n
    \n
  • 它包括 arrays [N]T,其中数组长度是类型的一部分,因此您的约束必须指定您想要捕获的所有可能的数组
  • \n
  • 它包括数组指针*[N]T,您无法在类型约束中轻松抽象它
  • \n
  • 它包括映射,这迫使您捕获键K和值V,它们可能与 相同,也可能不同T。另外,K必须实施comparable.
  • \n
\n

所以你必须写这样的东西:

\n
type Measurable[T any, K comparable, V any] interface {\n    ~string | ~[]T | ~map[K]V | ~chan T\n}\n
Run Code Online (Sandbox Code Playgroud)\n

值得注意的是,它不包含数组,并且不明显捕获指针文字,例如要匹配[]*int,您必须实例T*int

\n

你可能会简化V一下:

\n
type Measurable[T any, K comparable] interface {\n    ~string | ~[]T | ~map[K]T | ~chan T\n}\n
Run Code Online (Sandbox Code Playgroud)\n

功能LenOf则变为:

\n
func LenOf[T any, K comparable, M Measurable[T, K]](m M) int {\n    return len(m)\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但你仍然需要提供K,所以你必须实例化LenOf在调用站点使用映射键的虚假类型进行实例化:

\n
LenOf[string, int]("foo")\n//            ^ actually useless\n
Run Code Online (Sandbox Code Playgroud)\n

并且您也无法利用参数的类型推断。

\n

结论:只需使用len. 设计您的泛型函数以使用支持长度的类型文字,或者仅将您的函数合理期望处理的那些类型添加到约束中。

\n