Go 標準庫依賴的那些 modules

對於程序員來說,編寫的代碼依賴標準庫是 “天經地義” 的事情。標準庫在程序員眼中就是高質量的代名詞,也是最值得信賴的非自己所寫的代碼,當然更是代碼包依賴關係鏈條上的最後一環,即所有直接或間接依賴的第三方 module 最終都會依賴標準庫。

前兩天組內學習 rust[1] 的小夥伴說 rust 的標準庫還依賴第三方庫 (注:我對 rust 瞭解不深,尚未證實),這引發了我的一個疑問: Go 標準庫是否依賴其他 modules 呢?在這一短篇中,我就來探究一下

注:本文使用的 Go 版本爲 Go 1.19[2]。

衆所周知,Go 於 1.11 版本引入 go modules[3],如今 Go module 已經完全替代掉原先的 gopath 構建模式,成爲了 Go 源碼的標準構建模式。

相應的,Go 標準庫也在 Go 1.13 版本 [4] 中採用了 Go module 構建,加入了 go.mod 文件,第一版標準庫的 go.mod 文件內容如下:

module std
  
go 1.12

require (
    golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8
    golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
    golang.org/x/sys v0.0.0-20190529130038-5219a1e1c5f8 // indirect
    golang.org/x/text v0.3.2 // indirect
)

我們看到 Go 標準庫的 module path 爲 std。不過就像開篇說的那樣,很多 gopher 認爲標準庫應該是依賴鏈的末端,但從 go.mod 文件的內容來看,Go 標準庫也有自己的依賴

我們再來看看 Go 1.19 版本 [5] 中 go.mod 的內容:

module std
  
go 1.19

require (
    golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8
    golang.org/x/net v0.0.0-20220517181318-183a9ca12b87
)

require (
    golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098 // indirect
    golang.org/x/text v0.3.8-0.20220509174342-b4bca84b0361 // indirect
)

我們看到:和 Go 1.13 版本相比,Go 標準庫的 go.mod 將直接依賴和間接依賴 (也叫傳遞依賴) 分開放在不同的 require block 中,這是因爲 Go 1.17 版本增加的 module 依賴圖修剪特性 [6]。

但從 Go 標準庫依賴的 modules 來看,和 Go 1.13 相比,Go 標準庫依賴的 modules 並沒有變化。

Go 標準庫依賴的是什麼 modules 呢?我們看到其依賴的 module 都在 golang.org/x 這個路徑下,這是 Go 核心團隊自己維護的非標準庫 module 的 Canonical import paths[7] 的前綴路徑。golang.org/x 這個前綴路徑下的包有不少,如下圖所示:

其中,主要的可以被 import 的功能 module 包括:

注:exp 下面的包儘量不用,或務必謹慎使用,這裏實驗性包居多,API 接口和具體實現變化可能性很大。還有一些是廢棄不再維護的。

那 Go 標準庫爲什麼會直接依賴 crypto 和 net 這兩個 modules 呢?

我的理解是網絡與密碼學是兩個變化較快的領域,同時也是兩個十分重要的領域,尤其是在如今對安全十分重視的雲原生時代。一些新的密碼學算法、網絡技術規範 (RFC) 在不斷的出現並持續演進,這些技術在未成熟前尚不適合放入標準庫,那麼在標準庫之外由 Go 核心團隊維護一個 “與時俱進” 的庫就十分必要。等成熟後,在標準庫中設計並提供穩定接口並引用 golang.org/x/abc 下的實現就可以很快實現對某成熟網絡技術或密碼學技術的穩定支持,當年 Go 1.6 版本對 http/2 的支持就是這麼做的 [8]。

那麼 Go 標準庫都依賴了哪些具體的包了呢?我們可以看一下 $GOROOT/src/vendor 下面的 modules.txt:

# golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8
## explicit; go 1.17
golang.org/x/crypto/chacha20
golang.org/x/crypto/chacha20poly1305
golang.org/x/crypto/cryptobyte
golang.org/x/crypto/cryptobyte/asn1
golang.org/x/crypto/curve25519
golang.org/x/crypto/curve25519/internal/field
golang.org/x/crypto/hkdf
golang.org/x/crypto/internal/poly1305
golang.org/x/crypto/internal/subtle
# golang.org/x/net v0.0.0-20220517181318-183a9ca12b87
## explicit; go 1.17
golang.org/x/net/dns/dnsmessage
golang.org/x/net/http/httpguts
golang.org/x/net/http/httpproxy
golang.org/x/net/http2/hpack
golang.org/x/net/idna
golang.org/x/net/lif
golang.org/x/net/nettest
golang.org/x/net/route
# golang.org/x/sys v0.0.0-20220614162138-6c1b26c55098
## explicit; go 1.17
golang.org/x/sys/cpu
# golang.org/x/text v0.3.8-0.20220509174342-b4bca84b0361
## explicit; go 1.17
golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm

modules.txt 是 go mod vendor 命令生成的,也是項目依賴包的完全列表,包括間接依賴的包。

我們可以通過 go mod why 命令查詢爲什麼標準庫要依賴這些 module 以及 package,以 golang.org/x/crypto 這個 module 爲例:

$go mod why -m golang.org/x/crypto         
# golang.org/x/crypto
crypto/tls
golang.org/x/crypto/chacha20poly1305

我們看到是 crypto/tls 包依賴了 golang.org/x/crypto 這個 module,但 why 只會輸出標準庫中依賴 x/crypto module 的一個包而已,並非全部。同理我們也可以查看 modules.txt 某個具體的包爲何要被依賴,以 golang.org/x/net/dns/dnsmessage 爲例:

$go mod why golang.org/x/net/dns/dnsmessage
# golang.org/x/net/dns/dnsmessage
net
golang.org/x/net/dns/dnsmessage

我們看到 net 包依賴了 dnsmessage 這個包。

綜上,我們知道了 Go 標準庫也是會依賴的,但其依賴的 module 被嚴格限制在 Go 核心團隊自己維護的 golang.org/x 下面的少數 module,因此我們依然可以完全信任 Go 標準庫,相信後續 Go 標準庫也會一直保證實現的高質量。

Gopher Daily(Gopher 每日新聞) 歸檔倉庫 - https://github.com/bigwhite/gopherdaily

我的聯繫方式:

商務合作方式:撰稿、出書、培訓、在線課程、合夥創業、諮詢、廣告合作。

參考資料

[1]  學習 rust: https://tonybai.com/2021/03/15/rust-vs-go-why-they-are-better-together

[2]  Go 1.19: https://tonybai.com/2022/08/22/some-changes-in-go-1-19

[3]  Go 於 1.11 版本引入 go modules: https://tonybai.com/2018/11/19/some-changes-in-go-1-11/

[4]  Go 1.13 版本: https://tonybai.com/2019/10/27/some-changes-in-go-1-13/

[5]  Go 1.19 版本: https://tonybai.com/2022/08/22/some-changes-in-go-1-19

[6]  Go 1.17 版本增加的 module 依賴圖修剪特性: https://tonybai.com/2021/08/19/go-module-changes-in-go-1-17

[7]  Canonical import paths: https://tonybai.com/2014/11/04/some-changes-in-go-1-4

[8]  Go 1.6 版本對 http/2 的支持就是這麼做的: https://tonybai.com/2016/02/21/some-changes-in-go-1-6

[9]  “Gopher 部落” 知識星球: https://wx.zsxq.com/dweb2/index/group/51284458844544

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/n4Xvjrze4lWx8HdSMN20tg