开发者生态
morning
Go 1.27 中的泛型方法
2026-08-21
1 阅读
约3分钟阅读
EspressoGPT
字号:
当 Go 1.18 在 2022 年引入泛型时,它为函数和结构体带来了泛型类型参数,但省略了方法。随着 Go 1.27 的发布,这个长期存在的限制已被消除。方法现在可以定义自己的类型参数,而无需将它们添加到接收结构中。为什么引入此更改如果您想创建一个保存通用值的图形节点,您可以像这样实现它: type Node [ T any ] struct { value T } 想象一下添加一个方法 Map ,将类型 T 的节点转换为另一种类型 U 的节点。在 Go 1.27 之前,您被迫将 U 直接添加到 Node 结构本身: type Node [ T any , U any ] struct { value T } func ( n * Node [ T , U ]) Map () Node [ T , U ] { // ... } 将 U 添加到结构本身是糟糕的设计,因为 U 是特定于 Map 的类型参数。即使其他方法不会使用 U ,它们仍然必须将其保留在接收器声明中。唯一的解决方法是将 Map 实现为包级函数而不是方法,因为函数可以定义自己的类型参数。但方法却不能,导致 API 代码设计笨拙且不惯用。从 Go 1.27 开始,U 可以专门在 Map 方法上定义: func ( n * Node [ T ]) Map [ U any ]() Node [ U ] { // ... } 为什么花了这么长时间?答案在于 Go 中泛型的实现方式。编译器主要使用单态化来处理泛型,这意味着它将为所使用的每个特定类型创建泛型结构或函数的副本。因为在某些时候,泛型的抽象概念需要转换为直接的机器代码。然而,Go 的接口系统是在运行时工作的。传递给接口参数的值的特定类型在程序运行时解析。这种动态调度与编译时解析的泛型发生冲突。考虑一下如果我们想在接口中声明我们的 Map 方法会发生什么: type Mapper interface { Map [ T any , U any ]( element T ) U } 为了使这项工作正常进行,运行时要么需要一个即时编译器来动态生成特定类型的机器代码,要么需要预先为每种可能的类型创建所述副本,从而导致二进制文件大量膨胀。最终,Go 团队决定将泛型方法与接口分开。 Go 1.27 允许在具体类型上使用泛型方法,但不允许在接口上使用泛型方法。这种区别就是为什么上面的例子无法编译以及为什么围绕它的讨论花了一段时间的原因。进一步阅读
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱