博客 / 詳情

返回

Go 1.20要來了,看看都有哪些變化-第1篇

前言

Go官方團隊在2022.12.08發佈了Go 1.20 rc1(release candidate)版本,Go 1.20的正式release版本預計會在2023年2月份發佈。

讓我們先睹為快,看看Go 1.20給我們帶來了哪些變化。(文末有彩蛋!)

安裝方法:

$ go install golang.org/dl/go1.20rc1@latest
$ go1.20rc1 download

這是Go 1.20版本更新內容詳解的第1篇,歡迎大家關注公眾號,及時獲取本系列最新更新。

Go 1.20發佈清單

和Go 1.19相比,改動內容適中,主要涉及語言(Language)、可移植性(Ports)、工具鏈(Go Tools)、運行時(Runtime)、編譯器(Compiler)、彙編器(Assembler)、鏈接器(Linker)和核心庫(Core library)等方面的優化。

我們逐個看看具體都有哪些變化。

語言變化

Go 1.20在語言層面帶來了4個變化。

slice轉數組

Go1.17在語言層面開始支持將slice轉為指向數組的指針。

示例如下:

s := make([]byte, 2, 4)
// 將s這個slice轉為指向byte數組的指針s0
// 其中[0]byte裏的0表示數組的長度,雖然長度為0,但值不等於nil
s0 := (*[0]byte)(s)      // s0 != nil
fmt.Printf("%T")
// 將s[1:]這個slice轉為指向byte數組的指針s1
// s1指向的數組的長度為1
s1 := (*[1]byte)(s[1:])  // &s1[0] == &s[1]
// 將s這個slice轉為指向byte數組的指針s2
// s2指向的數組的長度為2 
s2 := (*[2]byte)(s)      // &s2[0] == &s[0]
// 將s這個slice轉為指向byte數組的指針s4
// s4指向的數組的長度為4 
s4 := (*[4]byte)(s)      // panics: len([4]byte) > len(s)

注意:slice轉為指向數組的指針時,如果數組定義的長度超過了slice的長度,會拋panic。

所以上面s4 := (*[4]byte)(s)這行代碼雖然可以編譯通過,但是會出現runtime panic。

Go 1.20之前不支持將slice直接轉為數組,如果要轉,得先轉為指向數組的指針,再轉為數組,如下面代碼所示:

s := make([]byte, 2, 4)
s[0] = 100

s1 := (*[1]byte)(s[1:]) // &s1[0] == &s[1]
s2 := (*[2]byte)(s)     // &s2[0] == &s[0]
fmt.Printf("%T, %v, %p, %p\n", s1, s1[0], &s1[0], &s[1])
fmt.Printf("%T, %v, %v, %p\n", s2, s2[0], &s2[0], s)
// a1數組裏元素的地址和s1指向的數組的元素地址不一樣,a2同理
a1 := *s1
a2 := *s2
fmt.Printf("%T, %v, %p, %p\n", a1, a1[0], &a1[0], &s1[0])
fmt.Printf("%T, %v, %p, %p\n", a2, a2[0], &a2[1], &s2[1])

從Go 1.20開始,支持將slice直接轉為數組,如下面代碼所示:

s := make([]byte, 2, 4)
s[0] = 100
s1 := [1]byte(s[1:])
s2 := [2]byte(s)
// s1數組裏元素的地址和s指向的數組的元素地址不一樣,s2同理
fmt.Printf("%T, %v, %p, %p\n", s1, s1[0], &s1[0], &s[1])
fmt.Printf("%T, %v, %v, %p\n", s2, s2[0], &s2[0], s)

總結:

  • slice轉為指向數組的指針後,這個指針會指向和slice相同的地址空間
  • slice轉為數組時,會把slice底層數組的值拷貝一份出來。轉換後得到的數組的地址空間和slice底層數組空間不一樣。

還有幾個語法細節可以參考如下代碼示例:

var t []string
t0 := [0]string(t)       // ok for nil slice t
t1 := (*[0]string)(t)    // t1 == nil
t2 := (*[1]string)(t)    // panics: len([1]string) > len(t)

u := make([]byte, 0)
u0 := (*[0]byte)(u)      // u0 != nil

Comparable類型

Go泛型裏comparable這個類型約束(type constraint)有個坑,就是和Go語言裏定義的可比較類型(Comparable types)並不一致。

什麼是comparable types,簡單來説就是可以用==!=來進行比較的類型就是comparable types。

The equality operators == and != apply to operands that are comparable.

The ordering operators <, <=, >, and >= apply to operands that are ordered.

有些可比較類型的變量不能作為類型實參(type argument)賦值給聲明瞭comparable類型約束的類型參數(type parameter)。

例如Go語言説明裏有如下這段內容:

Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

這裏明確指出,接口類型的值是可比較的,但是我們不能把2個interface作為類型實參給到類型參數。

參考如下代碼示例:

// example4.g0
package main

import "fmt"

func IsEqual[T comparable](a T, b T "T comparable") bool {
    return a == b
}

func main() {
    var a interface{} = 1
    var b interface{} = []int{1}
    fmt.Println(a == b) // false
  // go1.20之前的版本編譯報錯,go1.20開始支持
    fmt.Println(IsEqual(a, b)) 
}

對於上面最後一行代碼,Go 1.20之前的版本編譯報錯。

$ go1.18 run example4.go
./example4.go:13:21: interface{} does not implement comparable

因為Go 1.20之前的版本認為空接口類型interface{}並沒有實現comparable類型約束,不能作為類型實參傳給類型參數。

從Go 1.20版本開始,不會編譯報錯,因為interface類型是comparable type,程序執行結果如下:

$ go1.20rc1 run example4.go
false
false

具體哪些類型是comparable type可以參考:Comparable types 裏的説明。

unsafe包

Go 1.17版本在unsafe package裏引入了Slice函數,如下所示:

func Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType

在Go 1.20版本里,標準庫unsafe package定義了3個新的函數:

func SliceData(slice []ArbitraryType) *ArbitraryType
func String(ptr *byte, len IntegerType) string
func StringData(str string) *byte

有了這4個函數,可以構造和解構slice和string。

具體細節可以參考:https://tip.golang.org/ref/sp...。

值比較

Go語言説明現在明確指出結構體變量的值每次只比較一個字段,字段比較的順序和字段在結構體裏定義的順序保持一致。

一旦某個字段的值比較出現不一致,就會馬上停止比較。

以前的説明可能會讓Go開發者有誤解,以為結構體變量的比較需要比較所有字段,實際並不是。

類似的,數組的比較也是每次只比較一個元素,按照數組的下標索引由小到大逐個比較數組裏每個元素的值。

這塊只是改了説明而已,對大家的代碼沒有任何影響。

可移植性

Darwin and iOS

Go 1.20將會成為支持macOS 10.13 High Sierra和10.14 Mojave的最後一個版本。

如果未來想在mac電腦上使用Go 1.21或者更新的Go版本,只能用macOS 10.15 Catalina和更新的macOS版本。

FreeBSD/RISC-V

Go 1.20增加了對於RISC-V架構在FreeBSD操作系統的實驗性支持。

GOOS=freebsd
GOARCH=riscv64

總結

下一篇會介紹Go 1.20在Go Tool工具鏈、運行時、編譯器、彙編器、鏈接器和核心庫的優化工作,有一些內容值得學習,歡迎大家保持關注。

開源地址

文章和示例代碼開源在GitHub: Go語言初級、中級和高級教程。

公眾號:coding進階。關注公眾號可以獲取最新Go面試題和技術棧。

個人網站:Jincheng's Blog。

知乎:無忌。

福利

我為大家整理了一份後端開發學習資料禮包,包含編程語言入門到進階知識(Go、C++、Python)、後端開發技術棧、面試題等。

關注公眾號「coding進階」,發送消息 backend 領取資料禮包,這份資料會不定期更新,加入我覺得有價值的資料。還可以發送消息「進羣」,和同行一起交流學習,答疑解惑。

最後送上一個彩蛋,Go標準庫的腦圖,想學習Go標準庫的可以參考這個來。

References

  • https://tip.golang.org/doc/go...
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.