我正在尝试为 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)
为什么?内置len已经是“通用的”。
话虽如此,让我们看看为什么定义这样的约束是一个坏主意。Go 规范有一段 \xe2\x80\x94 Length andcapacity,可以帮助:
\n\n\n如果参数类型是类型参数 P,则调用
\nlen(e)(或cap(e)分别)必须对于 P 的类型集中的每个类型有效。结果是参数的长度(或容量),该参数的类型对应于实例化 P 的类型参数。
为“可测量”类型编写包罗万象的约束的问题是:
\n[N]T,其中数组长度是类型的一部分,因此您的约束必须指定您想要捕获的所有可能的数组*[N]T,您无法在类型约束中轻松抽象它K和值V,它们可能与 相同,也可能不同T。另外,K必须实施comparable.所以你必须写这样的东西:
\ntype Measurable[T any, K comparable, V any] interface {\n ~string | ~[]T | ~map[K]V | ~chan T\n}\nRun Code Online (Sandbox Code Playgroud)\n值得注意的是,它不包含数组,并且不明显捕获指针文字,例如要匹配[]*int,您必须实例T化*int。
你可能会简化V一下:
type Measurable[T any, K comparable] interface {\n ~string | ~[]T | ~map[K]T | ~chan T\n}\nRun Code Online (Sandbox Code Playgroud)\n功能LenOf则变为:
func LenOf[T any, K comparable, M Measurable[T, K]](m M) int {\n return len(m)\n}\nRun Code Online (Sandbox Code Playgroud)\n但你仍然需要提供K,所以你必须实例化LenOf在调用站点使用映射键的虚假类型进行实例化:
LenOf[string, int]("foo")\n// ^ actually useless\nRun Code Online (Sandbox Code Playgroud)\n并且您也无法利用参数的类型推断。
\n结论:只需使用len. 设计您的泛型函数以使用支持长度的类型文字,或者仅将您的函数合理期望处理的那些类型添加到约束中。