1. 程式人生 > >golang1.16新特性速覽

golang1.16新特性速覽

今天是假期最後一天,明天起大家也要陸續復工了。golang1.16也在今天正式釋出了。 原定計劃是2月1號年前釋出的,不過遲到也是golang的老傳統了,正好也趁著最後的假期快速預覽一下golang1.16的新特性吧。

本文索引

  • 語言內建的資源嵌入支援
  • 支援arm64
  • go modules的新特性
    • GO111MODULE現在預設為on
    • go build不在更改mod相關檔案
    • go install的變化
    • 新的GOVCS環境變數
    • 相對路徑匯入不在被允許
  • 標準庫的變化
    • testing
    • ioutils包已經廢棄
    • tcp半連線佇列擴容
    • 重大更新io/fs
  • 其他改進
## 語言內建的資源嵌入支援 之前市面上已經有很多把今天檔案嵌入golang二進位制程式的工具了,這次golang官方將這一功能加入了`embed`標準庫,從語言層面上提供了支援。 我之前以及寫了embed的使用教程,可以看[這裡](https://www.cnblogs.com/apocelipes/p/13907858.html)。 這兒還有一篇官方推薦的[教程](https://blog.carlmjohnson.net/post/2021/how-to-use-go-embed/)。 ## 支援arm64 m1晶片可謂是最近的焦點,golang自然也不會落下。 在golang1.16中官方已經支援`darwin/arm64`平臺,cgo和編譯成c語言可呼叫的動態/靜態連結庫的功能也已支援。同樣受益的還有bsd家族的arm64版本。 現在可以在新版mac上嘗試golang了。 不過plugin模式的支援仍在進行中,想要完整支援arm64還需要一段時間。 ## go modules的新特性 本次更新依舊帶來了許多modules的新特性。 ### GO111MODULE現在預設為on 1.16開始預設啟用modules,這在1.15的時候已經預告過了。現在GO111MODULE的預設值為on。 不過golang還是提供了一個版本的適應期,如果你還不習慣modules,可以把GO111MODULE設定回auto。在1.17中這個環境變數將會被刪除。 都1202年了,也該學學go modules怎麼用了。 ### go build不再更改mod相關檔案 以前的教程裡我提到過go build會自動下載依賴,這會更新mod檔案。 現在這一行為被禁止了。想要安裝、更新依賴只能使用go get命令,go build和go test將不會再做這類工作。 ### go install的變化 go install在1.16中也有了不小的變化。 首先是通過go install my.module/[email protected] 這樣在module末尾加上版本號,可以在不影響當前mod的依賴的情況下安裝golang程式。 go install是未來唯一可以安裝golang程式的命令,go get的編譯安裝功能現在可以靠`-d`選項關閉,而未來編譯安裝功能會從go get移除。 也就是說go的命令各司其職,不再長臂管轄了。 ### 新的GOVCS環境變數 新的GOVCS環境變數指定了golang用什麼版本控制工具下載原始碼。 其格式為:`GOVCS=:,[:, ...]` 其中module prefix為github.com等,而tool name就是版本控制工具的名字,比如git,svn。 一個更具體的例子是:`GOVCS=github.com:git,evil.com:off,*:git|hg` module prefix也可以用`*`通配任何模組的字首。 tool name還可以設定為all和off,all代表允許使用任何可用的工具,而off則表示不允許使用任何版本控制工具。 不過現在設定為off的模組的程式碼仍然可能會被下載。 更多的細節可以參考`go help vcs`。 ### 相對路徑匯入不在被允許 golang1.16開始禁止import匯入的模組以`.`開頭,模組路徑中也不允許出現任何非ASCII字元,所以下面的程式碼不再合法: ```golang import ( "./tools/factory" "../models/user" "some.pkg.com/殺馬特/音樂工廠" ) ``` 對非ASCII字元一如既往的不友好,不過也只能按規矩辦事了。 ## 標準庫的變化 golang1.16除了對標準庫進行通常的功能更新和修復,還引入了一些重大變化。 ### testing testing包主要的變化是在測試用例裡呼叫`os.Exit(0)`會從程式終止變成測試失敗。 比如這個: ```golang package main import ( "os" "testing" ) func TestXXX(t *testing.T) { t.Log("exit") os.Exit(0) } ``` 現在會是這樣的輸出: ```bash $ go test -v a_test.go === RUN TestXXX a_test.go:9: exit --- FAIL: TestXXX (0.00s) panic: unexpected call to os.Exit(0) during test [recovered] panic: unexpected call to os.Exit(0) during test goroutine 18 [running]: testing.tRunner.func1.2(0x51b920, 0x56cc28) /usr/local/go/src/testing/testing.go:1144 +0x332 testing.tRunner.func1(0xc000082600) /usr/local/go/src/testing/testing.go:1147 +0x4b6 panic(0x51b920, 0x56cc28) /usr/local/go/src/runtime/panic.go:965 +0x1b9 os.Exit(0x0) /usr/local/go/src/os/proc.go:68 +0x6d command-line-arguments.TestXXX(0xc000082600) /tmp/a_test.go:10 +0x76 testing.tRunner(0xc000082600, 0x54df18) /usr/local/go/src/testing/testing.go:1194 +0xef created by testing.(*T).Run /usr/local/go/src/testing/testing.go:1239 +0x2b3 FAIL command-line-arguments 0.004s FAIL ``` ### ioutils包已經廢棄 1.16已經標記`io/ioutil`為廢棄,函式被轉移到了os和io這兩個包裡,具體見下表: | ioutil舊函式 | 新函式 | | --- | --- | | Discard | io.Discard | | NopCloser | io.NopCloser | | ReadAll | io.ReadAll | | ReadDir | os.ReadDir | | ReadFile | os.ReadFile | | WriteFile | os.WriteFile | | TempDir | os.MkdirTemp | | TempFile | os.CreateTemp | 現在開始可以做移植了。 ### tcp半連線佇列擴容 在Linux kernel 4.1以前,golang設定tcp的listen佇列的長度是從/proc/sys/net/core/somaxconn獲取的,通常為4096。 而在4.1以後golang會直接設定半連線佇列的長度為`2^32 - 1`也就是4294967295。 更大的半連線佇列意味著可以同時處理更多的新加入請求,而且不用再讀取配置檔案效能也會略微提升。 ### 重大更新io/fs 1.16除了支援嵌入靜態資源外,最大的變化就是引入了io/fs包。 golang認為檔案的io操作是依賴於檔案系統(filesystem,fs)的,所以決定模仿Linux的vfs做一套基於fs的io介面。 這樣做的目的有三個: 1. os包應該專注於和系統互動而不是包含一部分io介面 2. io包和os包分別包含了io介面的一部分,導致互相依賴職責不清晰 3. 可以把有關聯的一部分檔案或者資料組成虛擬檔案系統,供通用介面處理提升程式的可擴充套件性,比如zip打包的檔案 所以io/fs誕生了。 fs包中主要包含了下面幾種資料型別(都是介面型別): | 名稱 | 作用 | | --- | --- | | FS | 檔案系統的抽象,有一個Open方法用來從FS開啟獲取檔案資料 | | DirEntry | 描述目錄專案(包含目錄自身)的資料結構 | | File | 描述檔案資料的結構,包含Stat,Read,Close方法 | | ReadDirFile | 在File的基礎上支援ReadDir,可以代表目錄自身 | | FileMode | 描述檔案型別,比如是通常檔案還是套接字或者是管道 | | FileInfo | 檔案的元資料,例如建立時間等 | 其中有一些介面和os包中的同名,實際上是os包引入fs包後起的別名。 對於FS,還有以下的擴充套件,以便增量描述檔案系統允許的操作: | 名稱 | 作用 | | --- | --- | | GlobFS | 增加Glob方法,可以用萬用字元查詢檔案 | | ReadDirFS | 增加ReadDir方法,可以遍歷目錄 | | ReadFileFS | 增加ReadFile方法,可以用檔名讀取檔案所有內容 | | StatFS | 增加Stat方法,可以獲得檔案/目錄的元資訊 | | SubFS | 增加Sub方法,Sub方法接受一個檔案/目錄的名字,從這個名字作為根目錄返回一個新的檔案系統物件 | fs包還提供了諸如Glob,WalkDir等傳統的檔案操作介面。 fs的主要威力在於處理zip、tar檔案,以及http的檔案介面時可以大幅簡化程式碼。而且新的`embed`靜態資源嵌入也是依賴fs實現的。 因為只是速覽的緣故,無法詳盡介紹io/fs包,你可以參考golang的文件或[這篇文章](https://benjamincongdon.me/blog/2021/01/21/A-Tour-of-Go-116s-iofs-package/)做進一步瞭解。 ## 其他改進 其他的改進包括Unicode更新到了13.0、新增加了runtime/metrics包已提供更好更規範的執行時資訊等。 同時1.16優化了連結器,現在它在linux/amd64上比1.15快了20-25%,記憶體佔用減少了5-15%。 在Windows上已經全面支援了地址空間佈局隨機化(ASLR),此前不支援將golang編譯為dll時啟用ASLR。 本次更新中語言本身沒有什麼變化。 更多資訊可以檢視[golang1.16 release notes](https://golang.org/doc/