服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

Go1.20 将禁止匿名接口循环导入!这是一次打破 Go1 兼容性承诺的真实案例

日期: 来源:脑子进煎鱼了收集编辑:陈煎鱼

大家好,我是煎鱼。

最近因为临近新版本发布节点,我在看 Go1.20 的新特性《spec: disallow anonymous interface cycles[1]》,发现了一个比较骚的操作...以前我都没想到可以这么用,还有点意思,分享给大家。

在 Go 规范中是允许将接口类型(interface{})内嵌到其他声明的接口当中的,也就是著名的套娃神器:组合。

套娃接口类型

Go 标准库中比较经典的例子如下:

type ReadCloser interface {
 Reader
 Closer
}

type Reader interface {
 Read(p []byte) (n int, err error)
}

type Closer interface {
 Close() error
}

实际上展开是:

type ReadCloser interface {
 interface {
     Read(p []byte) (n int, err error)
  }
 interface {
     Close() error
 }
}

一切都看起来如此美好,似乎很好的体现了 Go 的优秀之处。

计划是赶不上变化的。

匿名接口循环导入

在现实代码中,这种支持就存在着循环引用的用法。如下简单例子:

type I interface {
 m()
 interface {
     I
  }
}

这段代码,声明了接口类型 I,然后又包含了 m(),又包含接口 I。这会是一个 “永动机”,永远都不会停止。在开源的 GitHub 中,也真实存在着。

如项目 gozelus/zelus_rest[2] 的代码:

type MySQLDb interface {
 execSQL
 Table(ctx context.Context, name string) interface {
  whereSQL
  insertSQL
  selectSQL
  findSQL
  orderSQL
  clausesSQL
 }
 Begin() interface {
  MySQLDb
  Rollback()
  Commit()
 }
}

如项目 vetcher/go-astra[3] 的代码:

type ComplexInterface interface {
 A(a interface {
  B()
  ComplexInterface
 }) interface {
  C()
  D()
 }
}

这类写法其实非常迷惑人,这意味可以无限嵌套接口,并使用内在的方法。但作者在写这个代码时,可能目的并不是如此,导致被使用者错用。

这有没有问题

对外宣传简洁好用瀑布式编程的 Go,如此对匿名接口循环导入的支持,是否合规呢?

其实并不然。

早在 2016 年的 Proposal: Type Aliases[4] 中的 Type cycles 部分就对此有所定义:

在类型别名的提案中明确指出:别名必须能够 "向外展开",没有办法展开出像 T = *T 这样的类型别名。

套用到现在的问题来,如果上面的 T 就是 I(接口类型),那么同理可得 I = *I,这个过程是永远无法终止的。

社区讨论

在一番激烈讨论后,基于以下几点,决定接纳该提案,也就是在新版本中禁用 Go 匿名接口的循环导入,将其改为有限地扩展所有的嵌入式接口。

在禁用后,以下三种类似写法都会被拒绝。

第一种:

type B interface { I }
type I interface { m() interface { B } }

第二种:

type B = interface{ I }
type I interface{ m() interface{ B } }

第三种:

type B = interface{ I }
type I interface{ m() B }

Go1 兼容性承诺

最核心的是 Go1 兼容性承诺。从任何角度上来讲,禁用这个特性是破坏性变更(无法向后兼容),绝对是违反兼容性承诺的

大家认为在公共项目库中,基本没有人使用这种匿名接口循环导入的方式,用途很少(几乎为 0)除了上面提到的 gozelus/zelus_rest 项目,并且该模块似乎没什么人引用。

rsc 在综合了利弊后,认为把这个特性干掉,能更好的提高代码简洁性,确立了该特性的禁用,会和以往一样的推进节奏。

如下:

  • Go1.20:Go 编译器默认会拒绝这些接口循环,但可以使用 go build -gcflags=all=-d=interfacecycles 来进行构建,以确保旧代码的正常编译。如果在候选发布期间有人向 Go 团队报告大量损坏,将会取消此更改。
  • Go1.22:等到 1.22 版本后 -d=interfacecycles 标志将被删除,旧代码将不再构建该特性。如果有人报告问题,将可以讨论或是推迟删除,给予更多的改造时间。

链式调用模式

有一种经典的设计模式叫:链式调用,也有叫方法链的。例如在 etcd sdk 中,常常会在 Watch、Next 这类相关接口中见到。

在 Go 中可以这么写:

type Nexter interface { 
    Next(Input) (interface { Nexter }, error)
    Done() Output
}

一旦禁用后,就不能如此匿名嵌套了。

会强烈推荐使用如下方式:

type Nexter interface { 
    Next(Input) (Nexter, error)
    Done() Output
}

包括在 Node 这类节点声明时,也推荐如此:

type Node interface {
 Parent() Node
 FirstChild() Node
 Children() []Node
}

套娃也得套上名字,不能成为 “无名” 者。

总结

原先支持匿名接口的循环导入,本质上违背了 Go 一贯的简洁明了的设计理念。如果在 Go 工程中用的多,不注意就会产生次生影响,禁了也有好处。

目前该特性变更的代码已经提交。如果按照 rsc 的计划我们会在 Go1.20 或 Go1.21 看到这个新特性,Go1.22 或 Go1.24 将会正式移除。

值得关注的一点,Go团队为此打破了对 Go1 兼容性的承诺,做出了破坏性变更,在推进方式上采取的是渐进式的模式。

这仍然值得我们关注,毕竟...破窗效应?

推荐阅读

参考资料

[1]

spec: disallow anonymous interface cycles: https://github.com/golang/go/issues/56103

[2]

gozelus/zelus_rest: https://github.com/gozelus/zelus_rest/blob/master/core/db/db.go#L20

[3]

vetcher/go-astra: https://github.com/vetcher/go-astra/blob/master/test/assets/interfaces/source.go#L52

[4]

Proposal: Type Aliases: https://go.googlesource.com/proposal/+/master/design/18130-type-alias.md#type-cycles


关注和加煎鱼微信,

一手消息和知识,拉你进技术交流群

相关阅读

  • Go 标准库 net/http库知道吗?能说说优缺点吗?

  • 前言哈喽,大家后,我是asong;这几天看了一下Go语言标准库net/http的源码,所以就来分享一下我的学习心得;为什么会突然想看http标准库呢?因为在面试的时候面试官问我你知道Go语言的n
  • Go版本大于1.13,程序里这样做错误处理才地道

  • 大家好,这里是每周都在陪你进步的网管。之前写过几篇关于 Go 错误处理的文章,发现文章里不少知识点都有点落伍了,比如Go在1.13后对错误处理增加了一些支持,最大的变化就是支持了
  • 醒醒吧,未来不会有 Go2 了!

  • 大家好,我是煎鱼。马上春节了,节前最后一更。提前预祝大家春节快乐!本周末在学习的时候,看到 Go 团队大当家 Russ Cox(下称:rsc)在近期分享的《GopherCon 2022: Russ Cox - Compati
  • 紧急提醒!福州严查!

  • 2022年以来,全市市场监管部门深入开展整治校外教育培训机构不规范问题、减轻中小学生课外负担“点题整治”行动,查处了一批校外培训机构违法违规案件,促进全市校外培训机构健康
  • 突然窒息,仍在抢救……注意,最近高发

  • 1月14日湖北宜昌三峡中心人民医院西陵院区急诊科仅下半夜就收治了5名醉汉有的喝得人事不省有的呕吐得一塌糊涂在宜昌三峡中心人民医院伍家院区急诊科每天也都会收治醉汉所谓
  • 苦难的2022,仍需要避世的“主题公园”。

  • 点击收听-评《阿凡达2:水之道》:约5.3分杨超:5分《长江图》导演,《不要抬头》等19期嘉宾这便是“元宇宙电影”的雏形。当你们还在“科幻”或“电影”的维度讨论它是否合格之时,
  • 秒播TV端电视,近期最好用的版本!

  • 1、测试设备测评软件神袅电视软件适用TV端测评设备当贝X3测评结果无限制版本2、神袅电视【TV端】(软件链接在文章底部)很多小伙伴说,有没有新的电视直播分享一些?那么,那就安排一
  • UE4 材质练习 之 基础操作

  • 最近在学习 UE4 虚幻引擎,正好项目中也有用到,顺便记录一下相关内容,欢迎大家交流讨论,来不及解释了,快上车~~基础概念使用 UE 创建材质后,默认状态如下图所示,这里面有很多参数设
  • 聚合多功能,超强手机神器来了!

  • 1、测试设备测评软件红椒收音机软件适用安卓端测评设备小米12测评结果无需授权、海量资源2、红椒收音机【安卓端】(软件链接在文章底部)今天小编给大家整来一个安卓手机端全新

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • Go 标准库 net/http库知道吗?能说说优缺点吗?

  • 前言哈喽,大家后,我是asong;这几天看了一下Go语言标准库net/http的源码,所以就来分享一下我的学习心得;为什么会突然想看http标准库呢?因为在面试的时候面试官问我你知道Go语言的n
  • Go版本大于1.13,程序里这样做错误处理才地道

  • 大家好,这里是每周都在陪你进步的网管。之前写过几篇关于 Go 错误处理的文章,发现文章里不少知识点都有点落伍了,比如Go在1.13后对错误处理增加了一些支持,最大的变化就是支持了
  • 醒醒吧,未来不会有 Go2 了!

  • 大家好,我是煎鱼。马上春节了,节前最后一更。提前预祝大家春节快乐!本周末在学习的时候,看到 Go 团队大当家 Russ Cox(下称:rsc)在近期分享的《GopherCon 2022: Russ Cox - Compati
  • 三坑咨询|粉丝群&拼团交易群

  • 加入我们美好的时光里,我们彼此相伴成长,我们享受岁月静好,我们遇见,我们感恩,我们成长,感谢你,最美的时光,和我们在一起。QQ助力群:1009069207QQ出物群:1060724410QQ拼团群(不能发助力