自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go1.20 將禁止匿名接口循環(huán)導(dǎo)入!這是一次打破 Go1 兼容性承諾的真實案例

開發(fā) 前端
原先支持匿名接口的循環(huán)導(dǎo)入,本質(zhì)上違背了 Go 一貫的簡潔明了的設(shè)計理念。如果在 Go 工程中用的多,不注意就會產(chǎn)生次生影響,禁了也有好處。目前該特性變更的代碼已經(jīng)提交。如果按照 rsc 的計劃我們會在 Go1.20 或 Go1.21 看到這個新特性,Go1.22 或 Go1.24 將會正式移除。

大家好,我是煎魚。

最近因為臨近新版本發(fā)布節(jié)點,我在看 Go1.20 的新特性《spec: disallow anonymous interface cycles[1]》,發(fā)現(xiàn)了一個比較騷的操作...以前我都沒想到可以這么用,還有點意思,分享給大家。

在 Go 規(guī)范中是允許將接口類型(interface{})內(nèi)嵌到其他聲明的接口當(dāng)中的,也就是著名的套娃神器:組合。

套娃接口類型

Go 標(biāo)準(zhǔn)庫中比較經(jīng)典的例子如下:

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
}
}

一切都看起來如此美好,似乎很好的體現(xiàn)了 Go 的優(yōu)秀之處。

計劃是趕不上變化的。

匿名接口循環(huán)導(dǎo)入

在現(xiàn)實代碼中,這種支持就存在著循環(huán)引用的用法。如下簡單例子:

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

這段代碼,聲明了接口類型 I,然后又包含了 m(),又包含接口 I。這會是一個 “永動機”,永遠(yuǎn)都不會停止。在開源的 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()
}
}

這類寫法其實非常迷惑人,這意味可以無限嵌套接口,并使用內(nèi)在的方法。但作者在寫這個代碼時,可能目的并不是如此,導(dǎo)致被使用者錯用。

這有沒有問題

對外宣傳簡潔好用瀑布式編程的 Go,如此對匿名接口循環(huán)導(dǎo)入的支持,是否合規(guī)呢?

其實并不然。

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

圖片

在類型別名的提案中明確指出:別名必須能夠 "向外展開",沒有辦法展開出像 T = *T 這樣的類型別名。

套用到現(xiàn)在的問題來,如果上面的 T 就是 I(接口類型),那么同理可得 I = *I,這個過程是永遠(yuǎn)無法終止的。

社區(qū)討論

在一番激烈討論后,基于以下幾點,決定接納該提案,也就是在新版本中禁用 Go 匿名接口的循環(huán)導(dǎo)入,將其改為有限地擴展所有的嵌入式接口。

在禁用后,以下三種類似寫法都會被拒絕。

第一種:

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 兼容性承諾。從任何角度上來講,禁用這個特性是破壞性變更(無法向后兼容),絕對是違反兼容性承諾的。

大家認(rèn)為在公共項目庫中,基本沒有人使用這種匿名接口循環(huán)導(dǎo)入的方式,用途很少(幾乎為 0)除了上面提到的 gozelus/zelus_rest 項目,并且該模塊似乎沒什么人引用。

rsc 在綜合了利弊后,認(rèn)為把這個特性干掉,能更好的提高代碼簡潔性,確立了該特性的禁用,會和以往一樣的推進節(jié)奏。

如下:

  • Go1.20:Go 編譯器默認(rèn)會拒絕這些接口循環(huán),但可以使用go build -gcflags=all=-d=interfacecycles 來進行構(gòu)建,以確保舊代碼的正常編譯。如果在候選發(fā)布期間有人向 Go 團隊報告大量損壞,將會取消此更改。
  • Go1.22:等到 1.22 版本后-d=interfacecycles 標(biāo)志將被刪除,舊代碼將不再構(gòu)建該特性。如果有人報告問題,將可以討論或是推遲刪除,給予更多的改造時間。

鏈?zhǔn)秸{(diào)用模式

有一種經(jīng)典的設(shè)計模式叫:鏈?zhǔn)秸{(diào)用,也有叫方法鏈的。例如在 etcd sdk 中,常常會在 Watch、Next 這類相關(guān)接口中見到。

在 Go 中可以這么寫:

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

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

會強烈推薦使用如下方式:

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

包括在 Node 這類節(jié)點聲明時,也推薦如此:

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

套娃也得套上名字,不能成為 “無名” 者。

總結(jié)

原先支持匿名接口的循環(huán)導(dǎo)入,本質(zhì)上違背了 Go 一貫的簡潔明了的設(shè)計理念。如果在 Go 工程中用的多,不注意就會產(chǎn)生次生影響,禁了也有好處。

目前該特性變更的代碼已經(jīng)提交。如果按照 rsc 的計劃我們會在 Go1.20 或 Go1.21 看到這個新特性,Go1.22 或 Go1.24 將會正式移除。

值得關(guān)注的一點,Go團隊為此打破了對 Go1 兼容性的承諾,做出了破壞性變更,在推進方式上采取的是漸進式的模式。

這仍然值得我們關(guān)注,畢竟...破窗效應(yīng)?

責(zé)任編輯:武曉燕 來源: 腦子進煎魚了
相關(guān)推薦

2022-12-14 09:13:37

Go程序規(guī)范

2023-01-30 08:46:20

GoGo1兼容性

2023-01-27 19:11:40

GoGo1兼容性

2020-07-07 14:15:25

Go代碼數(shù)據(jù)

2023-02-26 22:47:45

Go管理內(nèi)存

2021-02-21 09:09:24

GoGOPATH代碼

2023-02-06 08:51:30

PGO編譯速度

2023-03-02 09:07:44

2025-03-06 08:54:24

泛型類型MapGo1

2023-08-29 08:55:45

Go1Go核心

2024-05-10 08:47:22

標(biāo)準(zhǔn)庫v2Go

2022-11-17 08:47:20

Go特性標(biāo)準(zhǔn)庫

2022-11-09 11:50:21

2025-03-12 00:22:00

2025-04-30 09:02:46

2021-12-15 12:59:56

Go泛型版Beta1

2022-10-17 00:07:55

Go語言標(biāo)準(zhǔn)庫

2023-04-17 19:43:54

兼容性測試軟件測試

2021-10-06 14:16:24

微軟Windows 11Android App

2021-12-20 10:15:16

zip密碼命令網(wǎng)絡(luò)安全
點贊
收藏

51CTO技術(shù)棧公眾號