Go?1.22版本新特性前瞻
引言
美國時(shí)間2023年12月20日,Go官方宣布Go 1.22rc1發(fā)布,開啟了為期2個(gè)多月的、常規(guī)的公測(cè)之旅,Go 1.22預(yù)計(jì)將于2024.2月份正式發(fā)布!
除了在官網(wǎng)下載Go 1.22rc1版本進(jìn)行新特性體驗(yàn)之外,我們還可以通過在線的Go Playground選擇“Go dev branch”來體驗(yàn)(相比下載安裝,在線版本體驗(yàn)會(huì)有一些局限):
注:關(guān)于Go的多種安裝方法,《Go語言第一課》專欄有系統(tǒng)全面的講解,歡迎訂閱閱讀。
本文將和大家一起看看Go 1.22都會(huì)帶來哪些新特性。不過由于目前為時(shí)尚早,下面列出的有些變化最終不一定能進(jìn)入到Go 1.22的最終版本中,所以切記一切變更點(diǎn)要以最終Go 1.22版本發(fā)布時(shí)為準(zhǔn)。
1. 語言變化
Go 1.22的語言特性變化主要是圍繞for loop的。
1.1 loopvar試驗(yàn)特性轉(zhuǎn)正
在Go 1.21版本中,作為試驗(yàn)特性loopvar在Go 1.22中正式轉(zhuǎn)正。如果你還不知道這個(gè)特性是啥,我們來看一下下面這個(gè)最能說明問題的示例:
// go1.22-foresight/lang/for-range/for_range.go package main import ( "fmt" "sync" ) func main() { sl := []int{11, 12, 13, 14, 15} var wg sync.WaitGroup for i, v := range sl { wg.Add(1) go func() { fmt.Printf("%d : %d\n", i, v) wg.Done() }() } wg.Wait() }
我們分別用Go 1.22rc1和Go 1.21.0來運(yùn)行上面這段代碼:
// 使用go 1.22rc1的運(yùn)行結(jié)果: $go run for_range.go 4 : 15 1 : 12 0 : 11 3 : 14 2 : 13 // 使用go 1.21.0的運(yùn)行結(jié)果: $go run for_range.go 4 : 15 4 : 15 4 : 15 4 : 15 4 : 15
之所以存在差異,是因?yàn)镚o 1.22版本開始,for range語句中聲明的循環(huán)變量(比如這里的i和v)不再是整個(gè)loop一份(loop var per loop),而是每次iteration都會(huì)有自己的變量(loop var per-iteration),這樣在Go 1.22中,for range中的goroutine啟動(dòng)的閉包函數(shù)中捕獲的變量是loop var per-iteration,這樣才會(huì)輸出5個(gè)不同的索引值和對(duì)應(yīng)的切片值。
注:關(guān)于Go 1.22版本之前的for range的坑,《Go語言第一課》專欄有圖文并茂的原理講解,歡迎訂閱閱讀。
那傳統(tǒng)的3-clause的for loop呢?其中的循環(huán)變量的語義是否也發(fā)生變化了呢?我們看下面示例:
// go1.22-foresight/lang/for-range/classic_for_loop.go package main import ( "fmt" "sync" ) func main() { sl := []int{11, 12, 13, 14, 15} var wg sync.WaitGroup for i := 0; i < len(sl); i++ { wg.Add(1) go func() { v := sl[i] fmt.Printf("%d : %d\n", i, v) wg.Done() }() } wg.Wait() }
我們依然分別用Go 1.22rc1和Go 1.21.0版本運(yùn)行這段代碼,得到的結(jié)果如下:
// 使用go 1.22rc1的運(yùn)行結(jié)果: $go run classic_for_loop.go 0 : 11 4 : 15 2 : 13 3 : 14 1 : 12 // 使用go 1.21.0的運(yùn)行結(jié)果: $go run classic_for_loop.go panic: runtime error: index out of range [5] with length 5 goroutine 20 [running]: main.main.func1() /Users/tonybai/test/go/go1.22-foresight/lang/for-range/classic_for_loop.go:14 +0xc9 created by main.main in goroutine 1 /Users/tonybai/test/go/go1.22-foresight/lang/for-range/classic_for_loop.go:13 +0x7f panic: runtime error: index out of range [5] with length 5 goroutine 19 [running]: main.main.func1() /Users/tonybai/test/go/go1.22-foresight/lang/for-range/classic_for_loop.go:14 +0xc9 created by main.main in goroutine 1 /Users/tonybai/test/go/go1.22-foresight/lang/for-range/classic_for_loop.go:13 +0x7f exit status 2
從輸出結(jié)果來看,3-clause的for語句中聲明的循環(huán)變量也變成了loop var per-iteration了。
在Go 1.22之前,go vet工具在遇到像上面代碼那樣在閉包中引用循環(huán)變量的情況時(shí)會(huì)給出警告,但由于Go 1.22的這個(gè)語義修正,go vet對(duì)于Go 1.22及以后版本(根據(jù)go.mod中的指示)的類似Go代碼將不再報(bào)錯(cuò)。
不過就像Russ Cox在spec: less error-prone loop variable scoping這一issue中提及那樣,該特性落地可能會(huì)帶來不兼容問題,即對(duì)存量代碼行為的破壞性改變。為此Go團(tuán)隊(duì)提供了一個(gè)名為bisect的工具,該工具可以檢測(cè)出存量代碼在for loop語義發(fā)生變更后是否會(huì)導(dǎo)致問題。不過該工具似乎只能與go test一起使用,也就是說你只能對(duì)那些被Go測(cè)試覆蓋到的for loop進(jìn)行檢測(cè)。
目前spec: less error-prone loop variable scoping這一issue還處于open狀態(tài),也沒有放入Go 1.22 milestone中,不知道后續(xù)是否還會(huì)存在變數(shù)!
1.2 range支持整型表達(dá)式
在Go 1.22版本中,for range后面的range表達(dá)式除了支持傳統(tǒng)的像數(shù)組、切片、map、channel等表達(dá)式外,還支持放置整型表達(dá)式,比如下面這個(gè)例子:
// lang/range-expr-support-integer/main.go func main() { n := 5 for i := range n { fmt.Println(i) } }
我們知道:for range會(huì)在執(zhí)行伊始對(duì)range表達(dá)式做一次求值,這里對(duì)n求值結(jié)果為5。按照新增的for range后接整型表達(dá)式的語義,對(duì)于整數(shù)值n,for range每次迭代值會(huì)從0到n-1按遞增順序進(jìn)行。上面代碼中的for range會(huì)從0迭代到4(5-1),我們執(zhí)行一下上述代碼就可以印證這一點(diǎn):
$go run main.go 0 1 2 3 4
如果n <= 0,則循環(huán)不運(yùn)行任何迭代。
這個(gè)新語法特性,可以理解為是一種“語法糖”,是下面等價(jià)代碼的“語法糖”:
for i := 0; i < 5; i++ { fmt.Println(i) }
不過,迭代總是從0開始,似乎限制了該語法糖的使用范圍。
1.3 試驗(yàn)特性:range-over-function iterators
在for range支持整型表達(dá)式的時(shí)候,Go團(tuán)隊(duì)也考慮了增加函數(shù)迭代器(iterator),不過前者語義清晰,實(shí)現(xiàn)簡(jiǎn)單。后者展現(xiàn)形式、語義和實(shí)現(xiàn)都非常復(fù)雜,于是在Go 1.22中,函數(shù)迭代器以試驗(yàn)特性提供,通過GOEXPERIMENT=rangefunc可以體驗(yàn)該功能特性。
在沒有函數(shù)迭代器之前,我們實(shí)現(xiàn)一個(gè)通用的反向迭代切片的函數(shù)可能是像這樣:
// lang/range-over-function-iterator/backward_iterate_slice_old.go func Backward(s []E) func(func(int, E) bool) { return func(yield func(int, E) bool) { for i := len(s)-1; i >= 0; i-- { if !yield(i, s[i]) { return } } return } }
下面是在Go 1.21.0版本中使用上面Backward函數(shù)的方式:
// lang/range-over-function-iterator/backward_iterate_slice_old.go func main() { sl := []string{"hello", "world", "golang"} Backward(sl)(func(i int, s string) bool { fmt.Printf("%d : %s\n", i, s) return true }) }
我們用Go 1.21.0運(yùn)行一下上述示例:
$go run backward_iterate_slice_old.go 2 : golang 1 : world 0 : hello
在以前版本中,這種對(duì)切片、數(shù)組或map中進(jìn)行元素迭代的情況在實(shí)際開發(fā)中非常常見,也比較模式化,但基于目前語法,使用起來非常不便。于是Go團(tuán)隊(duì)提出將它們與for range結(jié)合在一起的提案。有了range-over-function iterator機(jī)制后,我們就可以像下面這樣使用Backward泛型函數(shù)了:
// lang/range-over-function-iterator/backward_iterate_slice_new.go func main() { sl := []string{"hello", "world", "golang"} for i, s := range Backward(sl) { fmt.Printf("%d : %s\n", i, s) } }
相比于上面的老版本代碼,這也的代碼更簡(jiǎn)潔清晰了,使用Go 1.22rc1的運(yùn)行結(jié)果也與老版本別無二致:
$GOEXPERIMENT=rangefunc go run backward_iterate_slice_new.go 2 : golang 1 : world 0 : hello
但代價(jià)就是要理解什么樣原型的函數(shù)才能與for range一起使用實(shí)現(xiàn)函數(shù)迭代,這的確有些復(fù)雜,本文就不展開說了,有興趣的童鞋可以先看看有關(guān)range-over-function iterator的wiki先行了解一下。
2. 編譯器、運(yùn)行時(shí)與工具鏈
2.1 繼續(xù)增強(qiáng)PGO優(yōu)化
自Go 1.20版本引入PGO(profile-guided optimization)后,PGO這種優(yōu)化技術(shù)帶來的優(yōu)化效果就得到了持續(xù)的提升:Go 1.20實(shí)測(cè)性能提升僅為1.05%;Go 1.21版本發(fā)布時(shí),官方的數(shù)據(jù)是2%~7%,而Go 1.21編譯器自身在PGO優(yōu)化過后編譯速度提升約6%。
在Go 1.22中,官方給出的數(shù)字則是2%~14%,這14%的提升想必是來自Google內(nèi)部的某個(gè)實(shí)際案例。
2.2 inline和devirtualize
在Go 1.22中,Go編譯器可以更靈活的運(yùn)用devirtualize和inline對(duì)代碼進(jìn)行優(yōu)化了。
在面向?qū)ο蟮木幊讨?,虛擬函數(shù)是一種在運(yùn)行時(shí)動(dòng)態(tài)確定調(diào)用的函數(shù)。當(dāng)調(diào)用虛擬函數(shù)時(shí),編譯器通常會(huì)為其生成一段額外的代碼,用于在運(yùn)行時(shí)確定要調(diào)用的具體函數(shù)。這種動(dòng)態(tài)調(diào)度的機(jī)制使得程序可以根據(jù)實(shí)際對(duì)象類型來執(zhí)行相應(yīng)的函數(shù),但也帶來了一定的性能開銷。通過devirtualize優(yōu)化技術(shù),編譯器會(huì)嘗試在編譯時(shí)確定調(diào)用的具體函數(shù),而不是在運(yùn)行時(shí)進(jìn)行動(dòng)態(tài)調(diào)度。這樣可以避免運(yùn)行時(shí)的開銷,并允許編譯器進(jìn)行更多的優(yōu)化。
對(duì)應(yīng)到Go來說,就是在編譯階段將使用接口進(jìn)行的方法調(diào)用轉(zhuǎn)換為通過接口的實(shí)際類型的實(shí)例直接調(diào)用該方法。
注:我的《Go語言精進(jìn)之路》一書中有對(duì)通過接口調(diào)用方法的原理的詳盡說明,歡迎閱讀。
關(guān)于內(nèi)聯(lián)優(yōu)化,今年Austin Clements發(fā)起了inline大修項(xiàng)目,對(duì)Go編譯器中的內(nèi)聯(lián)優(yōu)化過程進(jìn)行全面調(diào)整,目標(biāo)是在Go 1.22中擁有更有效的、具有啟發(fā)能力的內(nèi)聯(lián),為后續(xù)內(nèi)聯(lián)的進(jìn)一步增強(qiáng)奠定基礎(chǔ)。該大修的成果目前以GOEXPERIMENT=newinliner試驗(yàn)特性的形式在Go 1.22中提供。
2.3 運(yùn)行時(shí)
運(yùn)行時(shí)的變化主要還是來自GC。
Go 1.22中,運(yùn)行時(shí)會(huì)將基于類型的垃圾回收的元數(shù)據(jù)放在每個(gè)堆對(duì)象附近,從而可以將Go程序的CPU性能提高1-3%。同時(shí),通過減少重復(fù)的元數(shù)據(jù)的優(yōu)化,內(nèi)存開銷也將降低約1%。不確定減少重復(fù)元數(shù)據(jù)(metadata)這一優(yōu)化是否來自對(duì)unique包的討論。
2.4 工具鏈
在Go工具鏈改善方面,首當(dāng)其沖的要數(shù)go module相關(guān)工具了。
在Go 1.22中,go work增加了一個(gè)與go mod一致的特性:支持vendor。通過go work vendor,可以將workspace中的依賴放到vendor目錄下,同時(shí)在構(gòu)建時(shí),如果module root下有vendor目錄,那么默認(rèn)的構(gòu)建是go build -mod=vendor,即基于vendor的構(gòu)建。
go mod init在Go 1.22中將不再考慮GOPATH時(shí)代的包依賴工具的配置文件了,比如Gopkg.lock。在Go 1.22版本之前,如果go module之前使用的是類似dep這樣的工具來管理包依賴,go mod init會(huì)嘗試讀取dep配置文件來生成go.mod。
go vet工具取消了對(duì)loop變量引用的警告,增加了對(duì)空append的行為的警告(比如:slice = append(slice))、增加了deferring time.Since的警告以及在log/slog包的方法調(diào)用時(shí)key-value pair不匹配的警告。
3. 標(biāo)準(zhǔn)庫
最后,我們來看看標(biāo)準(zhǔn)庫的變化。每次Go發(fā)布新版本,標(biāo)準(zhǔn)庫都是占更新的大頭兒,這里無法將所有變更點(diǎn)一一講解,僅說說幾個(gè)重要的變更點(diǎn)。
3.1 增強(qiáng)http.ServerMux表達(dá)能力
Go內(nèi)置電池,從誕生伊始就內(nèi)置了強(qiáng)大的http庫,不過長期以來http原生的ServeMux表達(dá)能力比較單一,不支持通配符等,這也是Go社區(qū)長期以來一直使用像gorilla/mux、httprouter等第三方路由庫的原因。
今年log/slog的作者Jonathan Amsterdam又創(chuàng)建了新的提案:net/http: enhanced ServeMux routing,提高h(yuǎn)ttp.ServeMux的表達(dá)能力。在新提案中,新的ServeMux將支持如下路由策略(來自http.ServeMux的官方文檔):
- "/index.html"路由將匹配任何主機(jī)和方法的路徑"/index.html";
- "GET /static/"將匹配路徑以"/static/"開頭的GET請(qǐng)求;
- "example.com/"可以與任何指向主機(jī)為"example.com"的請(qǐng)求匹配;
- "example.com/{$}"會(huì)匹配主機(jī)為"example.com"、路徑為"/"的請(qǐng)求,即"example.com/";
- "/b/{bucket}/o/{objectname...}"匹配第一段為"b"、第三段為"o"的路徑。名稱"bucket"表示第二段,"objectname"表示路徑的其余部分。
下面就是基于上面的規(guī)則編寫的示例代碼:
// lib/servemux/main.go func main() { mux := http.NewServeMux() mux.HandleFunc("/index.html", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, `match /index.html`) }) mux.HandleFunc("GET /static/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, `match "GET /static/"`) }) mux.HandleFunc("example.com/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, `match "example.com/"`) }) mux.HandleFunc("example.com/{$}", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, `match "example.com/{$}"`) }) mux.HandleFunc("/b/{bucket}/o/{objectname...}", func(w http.ResponseWriter, req *http.Request) { bucket := req.PathValue("bucket") objectname := req.PathValue("objectname") fmt.Fprintln(w, `match /b/{bucket}/o/{objectname...}`+":"+"bucket="+bucket+",objectname="+objectname) }) http.ListenAndServe(":8080", mux) }
我們使用curl對(duì)上述示例進(jìn)行一個(gè)測(cè)試(前提是在/etc/hosts中設(shè)置example.com為127.0.0.1):
$curl localhost:8080/index.html match /index.html $curl example.com:8080/static/abc match "example.com/" $curl localhost:8080/static/abc match "GET /static/" $curl example.com:8080/ match "example.com/{$}" $curl example.com:8080/b/mybucket/o/myobject/tonybai match "example.com/" $curl localhost:8080/b/mybucket/o/myobject/tonybai match /b/{bucket}/o/{objectname...}:bucket=mybucket,objectname=myobject/tonybai
從測(cè)試情況來看,不同路由設(shè)置之間存在交集,這就需要路由匹配優(yōu)先級(jí)規(guī)則。新版Go ServeMux規(guī)定:如果一個(gè)請(qǐng)求有兩個(gè)或兩個(gè)以上的模式匹配,則更具體(specific)的模式優(yōu)先。如果P1符合P2請(qǐng)求的嚴(yán)格子集,也就是說,如果P2符合P1及更多的所有請(qǐng)求,那么P1就比P2更具體。
舉個(gè)例子:"/images/thumbnails/"比"/images/"更具體,因此兩者都可以注冊(cè)。前者匹配以"/images/thumbnails/"開頭的路徑,后者則匹配"/images/"子樹中的任何其他路徑。
如果兩者都不更具體,那么模式就會(huì)發(fā)生沖突。為了向后兼容,這一規(guī)則有一個(gè)例外:如果兩個(gè)模式發(fā)生沖突,而其中一個(gè)模式有主機(jī)(host),另一個(gè)沒有,那么有主機(jī)的模式優(yōu)先(比如上面測(cè)試中的第二次curl執(zhí)行)。如果通過ServeMux.Handle或ServeMux.HandleFunc設(shè)置的模式與另一個(gè)已注冊(cè)的模式發(fā)生沖突,這些函數(shù)就會(huì)panic。
增強(qiáng)后的ServeMux可能會(huì)影響向后兼容性,使用GODEBUG=httpmuxgo121=1可以保留原先的ServeMux行為。
3.2 增加math/rand/v2包
在日常開發(fā)中,我們多會(huì)在生成隨機(jī)數(shù)的場(chǎng)景下使用math/rand包,其他時(shí)候使用的較少。但Go 1.22中新增了math/rand/v2包,我之所以將這個(gè)列為Go 1.22版本標(biāo)準(zhǔn)庫的一次重要變化,是因?yàn)檫@是標(biāo)準(zhǔn)庫第一次為某個(gè)包建立v2版本包,按照Russ Cox的說法,這次v2包的創(chuàng)建,為標(biāo)準(zhǔn)庫中的其他可能的v2包樹立了榜樣。創(chuàng)建math/rand/v2可以使Go團(tuán)隊(duì)能夠在一個(gè)相對(duì)不常用且風(fēng)險(xiǎn)較低的包中解決工具問題(如gopls、goimports等對(duì)v2包的支持),然后再轉(zhuǎn)向更常用、風(fēng)險(xiǎn)更高的包,如sync/v2或encoding/json/v2等。
新增rand/v2包的直接原因是清理math/rand并修復(fù)其中許多懸而未決的問題,特別是使用過時(shí)的生成器、慢速算法以及與crypto/rand沖突的問題,這里就不針對(duì)v2包舉具體的示例了,對(duì)該包感興趣的同學(xué)可以自行閱讀該包的在線文檔,并探索如何使用v2包。
同時(shí),該提案也為標(biāo)準(zhǔn)庫中的v2包的創(chuàng)建建立了一種模式,即v2包是原始包的子目錄,并且以原始包的API為起點(diǎn),每個(gè)偏離點(diǎn)都要有明確的理由。
想當(dāng)初,go module剛落地到Go中時(shí),Go module支持兩種識(shí)別major的兩種方式,一種是通過branch或tag號(hào)來識(shí)別,另外一種就是利用vN目錄來定義新包。當(dāng)時(shí)還不是很理解為什么要有vN目錄這種方式,現(xiàn)在從math/rand/v2包的增加來看,足以體現(xiàn)出當(dāng)初module設(shè)計(jì)時(shí)的前瞻性考量了。
3.3 大修Go execution tracer
Go Execution Tracer是解決Go應(yīng)用性能方面“疑難雜癥”的殺手锏級(jí)工具,它可以提供Go程序在一段時(shí)間內(nèi)發(fā)生的情況的即時(shí)視圖。這些信息對(duì)于了解程序隨時(shí)間推移的行為非常寶貴,可輔助開發(fā)人員對(duì)應(yīng)用進(jìn)行性能改進(jìn)。我曾在《通過實(shí)例理解Go Execution Tracer》中對(duì)其做過系統(tǒng)的說明。
不過當(dāng)前版本的Go Execution Tracer在原理和使用方面還存在諸多問題,Google的Michael Knyszek在年初發(fā)起了Execution tracer overhaul的提案,旨在對(duì)Go Execution Tracer進(jìn)行改進(jìn),使Go Execution Tracer可擴(kuò)展到大型Go部署的Go執(zhí)行跟蹤。具體目標(biāo)如下:
使跟蹤解析所需的內(nèi)存占用量?jī)H為當(dāng)前的一小部分。
支持可流式傳輸?shù)母?,以便在無需存儲(chǔ)的情況下進(jìn)行分析。
實(shí)現(xiàn)部分自描述的跟蹤,以減少跟蹤消費(fèi)者的升級(jí)負(fù)擔(dān)。
修復(fù)長期存在的錯(cuò)誤,并提供一條清理實(shí)現(xiàn)的路徑。
在近一年的時(shí)間里,Knyszek與Felix Geisendorfer、Nick Ripley、Michael Pratt等一起實(shí)現(xiàn)了該提案的目標(biāo)。
鑒于篇幅,這里就不對(duì)新版Tracer的使用做展開說明,有興趣的童鞋可結(jié)合《通過實(shí)例理解Go Execution Tracer》中的使用方法自行體驗(yàn)新版Tracer。
注:新版Tracer的設(shè)計(jì)文檔 - https://go.googlesource.com/proposal/+/ac09a140c3d26f8bb62cbad8969c8b154f93ead6/design/60773-execution-tracer-overhaul.md
3.4 其他
“出爾反爾” - syscall包:取消棄用(undeprecate)
自Go 1.4版本以來,syscall包新特性就已經(jīng)被凍結(jié),并在Go 1.11版本中被標(biāo)記為不推薦使用(deprecate)。Go團(tuán)隊(duì)推薦gopher使用golang.org/x/sys/unix或golang.org/x/sys/windows。syscall包的大多數(shù)功能都能被golang.org/x/sys包替代,除了下面這幾個(gè):
syscall.SysProcAttr(類型os/exec.Cmd.SysProcAttr) syscall.Signal(參考文獻(xiàn)os.Signal) syscall.WaitStatus(參考文獻(xiàn)os.(*ProcessState).Sys) syscall.Stat_t ... ...
由于syscall包已經(jīng)棄用,IDE等工具在開發(fā)人員使用上述內(nèi)容時(shí)總是得到警告!這引發(fā)了眾多開發(fā)人員的抱怨。為此,在Go 1.22版本中,syscall取消了棄用狀態(tài),但其功能特性依舊保持凍結(jié),不再添加新特性。
TCPConn to UnixConn:支持zerocopy
gnet作者Andy Pan的提案:TCPConn to UnixConn:支持zerocopy在Go 1.22落地,具體內(nèi)容可以看一下原始提案issue。
新增go/version包
在Go 1.21版本發(fā)布后,Go團(tuán)隊(duì)對(duì)Go語言的版本規(guī)則做了調(diào)整,并明確了Go語言的向前兼容性和toolchain規(guī)則,Go 1.22中增加go/version包實(shí)現(xiàn)了按照上述版本規(guī)則的Go version判斷,這個(gè)包既用于go工具鏈,也可以用于Gopher自行開發(fā)的工具中。
4. 小結(jié)
Go 1.22版本具有至少兩點(diǎn)重要的里程碑意義:
通過對(duì)loopvar語義的修正,開啟了Go已有“語法坑”的fix之路
通過math/rand/v2包樹立了Go標(biāo)準(zhǔn)庫建立vN版本的模式
“語法坑”fix是否能得到社區(qū)正向反饋還是一個(gè)未知數(shù),其導(dǎo)致的兼容性問題勢(shì)必會(huì)成為Go社區(qū)在升級(jí)到Go 1.22版本的重要考慮因素,即便決定升級(jí)到Go 1.22,嚴(yán)格的代碼審查和測(cè)試也是必不可少的。
最后,感謝Go團(tuán)隊(duì)以及所有Go 1.22貢獻(xiàn)者做出的偉大工作!
文本涉及的源碼可以在這里下載。
參考資料
-Go 1.22 Milestone - https://github.com/golang/go/milestone/298
以上就是Go 1.22新特性的詳細(xì)內(nèi)容,更多關(guān)于Go 1.22新特性的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang語言使用像JAVA?Spring注解一樣的DI和AOP依賴注入實(shí)例
這篇文章主要為大家介紹了Golang語言使用像JAVA?Spring注解一樣的DI和AOP依賴注入實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10使用golang在windows上設(shè)置全局快捷鍵的操作
最近在工作中,總是重復(fù)的做事,想著自己設(shè)置一個(gè)快捷鍵實(shí)現(xiàn)windows 剪貼板的功能,所以本文小編給大家分享了使用golang在windows上設(shè)置全局快捷鍵的操作,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下2024-02-02詳解Go語言中結(jié)構(gòu)體與JSON間的轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了Go語言中結(jié)構(gòu)體與JSON間的轉(zhuǎn)換,文中的示例代碼講解詳細(xì),對(duì)學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下2022-12-12Golang實(shí)現(xiàn)優(yōu)雅的將struct轉(zhuǎn)換為map
在項(xiàng)目實(shí)踐中,有時(shí)候我們需要將struct結(jié)構(gòu)體轉(zhuǎn)為map映射表,然后基于map做數(shù)據(jù)裁剪或操作。那么下面我來介紹下常用的兩種轉(zhuǎn)換方式,希望對(duì)大家有所幫助2023-01-01