为什么 Go 不支持泛型方法?

将 脚本之家 设为“星标⭐”

第一时间收到文章更新

图片

来源:脑子进煎鱼了(ID:eddycjy)

距离 Go1.18 正式发布泛型已经过去了 6 个版本,目前最新的版本是 Go1.24(2025.02 发布的)。

但目前 Go 仍然不支持泛型方法。这是为什么呢,是缺陷吗,还是设计如此?

为什么 Go 不支持泛型方法?

问题原因

结合 Go 泛型的提案《Type Parameters Proposal[1]》可以得知,这在现阶段是设计如此。也就是设计提案上就没有去支持泛型方法。

No parameterized methods 章节No parameterized methods 章节

官方设计文档给出以下缘由说明:

在既有的泛型设计中,Go 不允许方法,声明该方法特有的类型参数。接收者可以有类型参数,但方法不能添加任何类型参数。

难以实现的原因,官方给出了 4 个 package 互相引用的包来以此说明其问题点。

package1:

package p1// S is a type with a parameterized method Identity.type S struct{}// Identity is a simple identity method that works for any type.func (S) Identity[T any](v T "T any") T { return v }

package2:

package p2// HasIdentity is an interface that matches any type with a// parameterized Identity method.type HasIdentity interface { Identity[T any](T "T any") T}

package3:

package p3import "p2"// CheckIdentity checks the Identity method if it exists.// Note that although this function calls a parameterized method,// this function is not itself parameterized.func CheckIdentity(v interface{}) { if vi, ok := v.(p2.HasIdentity); ok {  if got := vi.Identity[int](0 "int"); got != 0 {   panic(got)  } }}

package4:

package p4import ( "p1" "p3")// CheckSIdentity passes an S value to CheckIdentity.func CheckSIdentity() { p3.CheckIdentity(p1.S{})}

在这个示例中,我们有一个 p1.S 类型,它包含一个参数化方法,同时还有一个 p2.HasIdentity 类型,它同样包含一个参数化方法。

p1.S 实现了 p2.HasIdentity,因此 p3.CheckIdentity 函数可以使用 int 作为参数调用 vi.Identity。当 p4.CheckSIdentity 调用时,这实际上会触发 p1.S.Identity[int] 的调用。

但是,问题出现了:p3 包对 p1.S 类型一无所知,并且在程序的其他部分可能并没有调用 p1.S.Identity。

因此按照现有的 Go 编译器的机机制是无法实例化 p1.S.Identity[int] 的,必须要在某个地方实例化过他才能做。

可能的方向

原提案作者 @Ian Lance Taylor 也思考了几种想象中的 Go 泛型方法。但都能找出比较大的缺陷。因此一直没有推进。

为什么 Go 不支持泛型方法?

分别是:遍历调用链、JIT、改语法。

遍历调用链

可以在链接时(link time)实例化它,但在一般情况下,这需要链接器遍历整个程序的调用图,以确定可能传递给 CheckIdentity 的类型集合。

但问题在于:即使完成了这样的遍历,在涉及类型反射(type reflection)时,仍然可能不够充分。因为反射可能会基于用户输入的字符串来查找方法,这意味着无法在编译或链接时完全确定所有可能的调用。

因此若要在链接时实例化所有参数化方法,就可能需要为每种可能的类型参数实例化所有参数化方法,而这显然是不可行的。

JIT

在运行时(run time)实例化,这通常意味着使用某种 JIT(即时编译)技术,或者通过某种基于反射的方式来执行。

但问题在于:这两种方法的实现都非常复杂,并且在运行时的性能开销可能会很高。

改语法

可以选择让参数化方法根本不实现接口(interface)。但如果这样做,我们又必须重新思考方法(method)的意义。

如果不考虑接口,任何参数化方法都可以简单地用一个参数化函数(generic function)来实现。

总结

截止目前而言,Go 泛型方法的支持还处于纠结的尴尬境地。Go 官方也承认该项特性看起来非常有用。

实际在语言设计上,需要确定思路和实现方向,以此达到较好的性能和开销体验。

参考资料

[1]

Type Parameters Proposal: https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#No-parameterized-methods~~~~

图片

  推荐阅读:

  • GO必知必会面试题汇总

  • 2024年最受欢迎的5个Go框架

  • Go排名创历史新高——将在3年内超越JavaScript

  • 2025 年 03 月编程语言排行榜|老古董语言强势回归,原因是相关开发人员退休了~

  • 领导最想裁掉的,不是“上班迟到,下班失联”的人,而是经常说这5句话的人

  • (0)
    wd123_cnwd123_cn
    上一篇 2025年3月19日 上午10:14
    下一篇 2025年3月19日

    相关文章

    • 三亚试行客房退订新规设专线接诉!曾有人提前20天退房被拒

      来源 | 南方都市报 3月9日,南都记者注意到,海南三亚市旅游行业协会联合会发布《三亚市住宿业客房预订退订指导意见(试行)》,自8日起试行,试行期一年。其中明确,非法定节假日期间,住宿业经营者、线上预定平台,应遵循客房入住前7日以上可无理由全额退款规则。此前,有网友反映预订了三亚的酒店,入住前20天提出退订,酒店拒绝退款。 3月7日,三亚市天涯区旅游和文化广…

      新闻资讯 2025年3月10日
    • 网站编辑的职责与挑战

      在数字化时代,网站编辑扮演着至关重要的角色。他们不仅需要具备扎实的文字功底,还要对网络技术有深入的了解。本文将从几个方面探讨网站编辑的职责与面临的挑战。 关键职责 网站编辑的首要任务是确保网站内容的准确性和时效性。他们需要定期更新新闻、文章和其他信息,以保持网站的活跃度和吸引力。此外,编辑还需对内容进行审核,确保所有发布的信息符合法律和道德标准。 技术挑战 …

      2025年3月12日
    • 跳跃翻车?小青蛙的“迷之落点”并非偶然

      青蛙,往往是跳跃的代名词。然而,并非所有青蛙都是跳跃高手,有些青蛙,就像Wild.Ark网站上展示的这只,甚至难以精准地控制自己的落点。这只青蛙的起跳能力堪称一流,但落地技巧着实有待提高。我们不禁要问,这只青蛙真的是协调性差到了极点,还是背后存在着某种科学的解释呢? 小型青蛙:混乱的落地是常态 将自己发射向一个移动的目标,这可不是一项精确的科学。许多青蛙都能…

      2025年3月25日
    • 福音歌手Marvin Sapp因教堂募捐“锁门”引发争议

      福音歌手、格莱美奖提名者Marvin Sapp牧师近日因一段在教堂募捐时指示招待员“锁门”的视频在社交媒体上引发争议。该视频拍摄于2024年7月,当时Sapp牧师在巴尔的摩举行的第109届世界五旬节大会上发表讲话。但这段视频在本周突然走红,引发了广泛的讨论和批评。 事件回顾: 视频中,58岁的Sapp牧师站在舞台上对与会者说:“这里有1000人……我说把门关…

      2025年3月29日
    • 创意DIY:复古烤盘变身为春季露台花盆

      随着春天的临近,许多人开始考虑如何美化他们的后院,无论是种植蔬菜园、添置新的“独处小屋”,还是在后院种植夜间盛开的花朵。然而,我们推荐从露台开始,通过一个简单的DIY园艺项目,为您的户外空间增添春天的气息。 创意DIY:复古烤盘变身花盆 DIY爱好者Jen在Instagram账号@tatertotsandjello上分享了一个巧妙的方法,将复古烤盘变身为露台…

      2025年3月8日