Go:支持通用方法

2026-05-27 1 阅读 f311a
golang / go 公共通知 您必须登录才能更改通知设置 Fork 19.1k Star 134k 规范:Go 的通用方法 #77273 新问题 复制链接 新问题 复制链接 已关闭 0 / 1 0 共 1 个问题已完成 封闭规范:Go 的通用方法 #77273 0 / 1 0 共 1 个问题已完成 复制链接 标签 LanguageChange 对 Go 语言的建议更改 对 Go 语言提案的建议更改提案已接受的泛型 问题与泛型相关 问题与泛型发布拦截器相关 里程碑 Go1.27 说明 griesemer 于 2026 年 1 月 22 日开放 问题正文操作 提案:Go 的泛型方法 观点变更。背景 为了清楚起见,下面我们使用术语“具体方法”(或者上下文清楚时仅使用“方法”)来描述像函数一样声明但具有接收器的非接口方法;我们使用术语“接口方法”来描述接口方法的名称和签名。根据当前规范,具体方法是带有接收器的函数。从语法上讲,这并不完全正确:虽然函数可以是泛型的,但方法却不能。他们不能自己声明新的类型参数;但它们可以具有通用类型的接收器(因此具有接收器类型的类型参数的方法本地名称)。造成这种差异的一个原因是,我们历来将方法的主要作用视为实现接口的一种手段:在具体方法上允许类型参数意味着我们也必须在接口方法上允许类型参数。 Go 不支持此类泛型接口方法,因为我们不知道如何实现(调用)它们,或者至少我们不知道如何有效地实现它们。具体来说,因为 Go 不需要具体类型来声明它实现的接口,而是一个动态属性,所以在编译时无法知道运行时需要无限可能的具体方法实例中的哪一个。这个缺点早已为人所知,并在最初的类型参数提案中进行了详细讨论。但具体方法不仅仅是实现接口的手段。方法是与类型关联的函数,并通过该类型的命名空间进行访问。因此,方法对于组织代码很有用,即使它们从未实现接口。此外,还有一个语法上的好处:x.a().b().c() 自然可以从左到右读取,而 c(b(a(x))) 则从内向外求值。方法的这两个方面也是众所周知的。由于这些原因,Go 用户长期以来一直要求通用方法,并且这个想法广泛流行。问题跟踪器上至少有两个提案:#49085(允许在方法中使用类型参数,2021 年 10 月,包含超过 900 个正面表情符号)#50981(向方法添加泛型,2022 年 2 月)到目前为止,我们一直拒绝添加通用具体方法,因为它总是暗示我们还需要通用接口方法。 Go FAQ 甚至指出“我们预计 Go 不会添加泛型方法”。也许需要改变一下观点:具体方法是一种语言特性,无论接口如何,它本身都是有用的。如果具体方法是带有接收器的函数,则通用具体方法可以是带有接收器的通用函数。此类方法不能通过接口调用的事实是一个正交方面:如果接口在语法上不能包含具有类型参数的方法,那么泛型具体方法自然不会在满足该接口方面发挥作用,因为不存在具有匹配类型参数的接口方法。请注意,原始类型参数提案也讨论了这种替代观点,如以下段落所示:“或者,我们可以决定参数化方法实际上并不实现接口,但这样我们就不太清楚为什么我们需要方法。如果我们忽略接口,则任何参数化方法都可以实现为参数化函数。”我们可能已经在这一点上得到了一些澄清:通用具体方法本身是有用的,即使它们不实现接口方法。建议 我们建议具体的方法声明应该看起来与函数声明完全相同,但带有接收器。具体来说,方法声明的语法应该像函数声明一样接受类型参数。函数声明的语法如下: FunctionDecl = " func " FunctionName [ TypeParameters ] Signature [ FunctionBody ] 。方法声明的语法应从(旧)更改: MethodDecl = " func " Receiver MethodName Signature [ FunctionBody ] 。至(新): MethodDecl = " func " 接收方 MethodName [ TypeParameters ] Signature [ FunctionBody ] 。或者,为了达到同样的效果,语法可以直接表达我们在散文中所说的内容:方法(声明)是带有接收者的函数(声明),并将两个产生式结合起来。这消除了语法产生式并强调了相似之处:Functio