Golang 泛型初探
- 本文作者: Pure White
- 本文連結: https://www.purewhite.io/2021/03/09/golang-generic-glance/
- 版權宣告: 本部落格所有文章除特別宣告外,均採用** BY-NC-SA 許可協議。轉載請註明出處!
Golang 的泛型實現已經正式合併到 master 分支上啦,之後也會在 master 分支上進行開發,那麼作為期待這個 feature 許久的 gopher,也想第一時間看看到底是如何實現的。
語法
這裡不過多講解泛型的語法,具體可以參考一下 https://github.com/golang/go/issues/43651 這個 issue。簡單來說,在 struct 和 func 的名字後面可以加一個 [] 裡面包含泛型的名字和限制條件,比如:
type container[T any] struct{
elem T
}
any 是個特殊的關鍵字,表示所有型別都可以。
示例程式
這裡我們寫一個示例程式來編譯成彙編,來看看泛型到底是怎麼實現的:
package main
type Stringer interface {
String() string
}
type Stringer2 interface {
Stringer
}
type container[T Stringer] struct {
s T
}
type stringerImpl struct {
s string
}
func (s stringerImpl) String() string {
return s.s
}
func loop[T any](s []T) {
for _, v := range s {
_ = v
}
}
func main() {
loop([]int{1, 2, 3, 4, 5})
c := container[Stringer2]{}
loop([]container[Stringer2]{c})
}
編譯成彙編
我們先基於 master 分支來編譯一個 go 出來,然後用這個 go 來執行以下命令:
$ go build -gcflags="-G=3 -l -S" main.go > main.s 2>&1
接下來去main.s
這個檔案看看,就會發現有這麼一段程式碼:
"".#loop[int] STEXT nosplit size=18 args=0x18 locals=0x0 funcid=0x0
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:39) TEXT "".#loop[int](SB), NOSPLIT|ABIInternal, $0-24
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:39) FUNCDATA $0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:39) FUNCDATA $1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:33) MOVQ "".s+16(SP), AX
0x0005 00005 (/Users/purewhite/go/src/local/study/main.go:33) XORL CX, CX
0x0007 00007 (/Users/purewhite/go/src/local/study/main.go:33) JMP 12
0x0009 00009 (/Users/purewhite/go/src/local/study/main.go:33) INCQ CX
0x000c 00012 (/Users/purewhite/go/src/local/study/main.go:33) CMPQ AX, CX
0x000f 00015 (/Users/purewhite/go/src/local/study/main.go:33) JGT 9
0x0011 00017 (/Users/purewhite/go/src/local/study/main.go:33) RET
0x0000 48 8b 44 24 10 31 c9 eb 03 48 ff c1 48 39 c8 7f H.D$.1...H..H9..
0x0010 f8 c3 ..
"".#loop[container[Stringer2]] STEXT nosplit size=21 args=0x18 locals=0x0 funcid=0x0
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:44) TEXT "".#loop[container[Stringer2]](SB), NOSPLIT|ABIInternal, $0-24
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:44) FUNCDATA $0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:44) FUNCDATA $1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
0x0000 00000 (/Users/purewhite/go/src/local/study/main.go:33) MOVQ "".s+16(SP), AX
0x0005 00005 (/Users/purewhite/go/src/local/study/main.go:33) TESTQ AX, AX
0x0008 00008 (/Users/purewhite/go/src/local/study/main.go:33) JLE 20
0x000a 00010 (/Users/purewhite/go/src/local/study/main.go:33) XORL CX, CX
0x000c 00012 (/Users/purewhite/go/src/local/study/main.go:33) INCQ CX
0x000f 00015 (/Users/purewhite/go/src/local/study/main.go:33) CMPQ AX, CX
0x0012 00018 (/Users/purewhite/go/src/local/study/main.go:33) JGT 12
0x0014 00020 (/Users/purewhite/go/src/local/study/main.go:33) RET
0x0000 48 8b 44 24 10 48 85 c0 7e 0a 31 c9 48 ff c1 48 H.D$.H..~.1.H..H
0x0010 39 c8 7f f8 c3 9....
再看 main 中呼叫的地方:
0x008c 00140 (/Users/purewhite/go/src/local/study/main.go:39) CALL "".#loop[int](SB)
...
0x00c0 00192 (/Users/purewhite/go/src/local/study/main.go:44) CALL "".#loop[container[Stringer2]](SB)
基本可以確定,go 的泛型目前的實現方案是在編譯時進行程式碼生成,這個方案雖然會降低編譯速度,但是在執行時是沒有效能損耗的。
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- Golang面試:泛型Golang面試泛型
- Go 1.18泛型的侷限性初探Go泛型
- Golang泛型是更快了還是慢了? - DoltHubGolang泛型
- 在Golang中使用泛型reduce函式 - gosamplesGolang泛型函式
- Golang modules 初探Golang
- golang拾遺:為什麼我們需要泛型Golang泛型
- Golang引入泛型:Go將Interface{}替換為“Any”Golang泛型
- 泛型類、泛型方法及泛型應用泛型
- 【java】【泛型】泛型geneticJava泛型
- 泛型類和泛型方法泛型
- 泛型--泛型萬用字元和泛型的上下限泛型字元
- TypeScript 泛型介面和泛型類TypeScript泛型
- Go 泛型之泛型約束Go泛型
- 泛型泛型
- 泛型最佳實踐:Go泛型設計者教你如何用泛型泛型Go
- golang聲音播放的初探Golang
- TypeScript 泛型型別TypeScript泛型型別
- 型別 VS 泛型型別泛型
- 泛型類、泛型方法、型別萬用字元的使用泛型型別字元
- 泛型(一)泛型
- 泛型(三)泛型
- 泛型(二)泛型
- 泛型(四)泛型
- 泛型(五)泛型
- Java泛型Java泛型
- 泛型viewmodle泛型View
- 泛型(Generic)泛型
- Go 泛型Go泛型
- 在Golang中使用泛型從任何map中獲取鍵的sliceGolang泛型
- 【譯】在非泛型類中建立泛型方法泛型
- Golang通脈之併發初探Golang
- 泛型型別(.NET 指南)泛型型別
- Java函式泛型List引數,操作泛型元素Java函式泛型
- Go 官方出品泛型教程:如何開始使用泛型Go泛型
- Java 泛型原理Java泛型
- java泛型一二Java泛型
- TypeScript 泛型相容TypeScript泛型
- C#泛型C#泛型