Golang中的泛型你真的了解嗎
Golang 在 1.18 版本更新后引入了泛型,這是一個重要的更新,Gopher 萬眾矚目,為 Golang 帶來了更多的靈活性和可重用性,同時也解決了在特定場景下 Golang 類型系統(tǒng)的限制。
今天,我們將深入探討泛型的概念、為什么需要泛型、泛型的語法,并探討如何在實踐中使用它。
go version >= 1.18
什么是泛型
泛型是一種在軟件開發(fā)中廣泛使用的編程概念,它允許開發(fā)者編寫可重用的代碼,而不需要考慮具體的數(shù)據(jù)類型。使用泛型,開發(fā)者可以編寫一些通用的算法和數(shù)據(jù)結構,這些算法和數(shù)據(jù)結構可以適用于不同類型的數(shù)據(jù),而不需要為每種類型都編寫一份專用的代碼。泛型的概念在其他許多編程語言中都有支持,比如 C++、Java、C# 等。
為什么需要泛型
假設我們需要實現(xiàn)一個返回一個 Map key 的 切片 []int -- MapKeysToInt。
func MapKeysToInt(m map[int]string) []int { r := make([]int, 0, len(m)) for k := range m { r = append(r, k) } return r }
可是這個函數(shù)只能接收map[int]string
類型的參數(shù),如果我們想支持 int8
類型的參數(shù),我們就需要再定義一個MapKeysToInt8 函數(shù)。
func MapKeysToInt8(m map[int8]string) []int8 { r := make([]int8, 0, len(m)) for k := range m { r = append(r, k) } return r }
如果要想支持 int64 類型切片就要定義 MapKeysToInt32 函數(shù),如果想支持 xxx 就需要定義一個 MapKeysToXXX...
我們會發(fā)現(xiàn)一遍一遍地編寫相同的功能非常的低效,
func MapKeysToInt32(m map[int32]string) []int32 { r := make([]int32, 0, len(m)) for k := range m { r = append(r, k) } return r }
Go1.18 之前我們可以使用反射的方式去實現(xiàn)上述問題,但是會降低代碼的執(zhí)行效率且失去編譯期的類型檢查等弊端。
Go1.18 之后我們可以用泛型來實現(xiàn)這一系列問題,eg:
// 當調用泛型函數(shù)的時候, 我們經??梢允褂妙愋屯茢唷? // 注意,當調用 MapKeys 的時候,我們不需要為 K 和 V 指定類型 - 編譯器會進行自動推斷 func MapKeys[K comparable, V any](m map[K]V) []K { r := make([]K, 0, len(m)) for k := range m { r = append(r, k) } return r } func main (){ var m = map[int]string{ 1: "2", 2: "4", 4: "8", } fmt.Println("keys m:", MapKeys(m)) var m2 = map[string]int{ "程序員祝融": 1, "李四": 2, "王五": 3, } fmt.Println("keys m2:", MapKeys(m2)) } // demo 運行結果: // keys m: [2 4 1] // keys m2: [李四 王五 程序員祝融]
泛型語法
泛型為Go語言添加了三個新的重要特性:
- 類型參數(shù)(形參、實參)
- 類型集
- 類型推斷
類型參數(shù)
之前我們定義函數(shù)時可以指定其形參,調用函數(shù)時傳實參,如下。
現(xiàn)在,Go 語言中的函數(shù)和類型支持添加類型參數(shù)。類型參數(shù)以類似于函數(shù)參數(shù)的方式進行定義,使用方括號 [] 包含一個或多個類型參數(shù)。
用泛型實現(xiàn)一個比較兩數(shù)大小的 demo ,eg:
func max[T int | int32 | int64 | float32](x, y T) T { if x >= y { return x } return y }
類型實例化
我們定義了一個 max 函數(shù),支持傳 int、int32、int64、float32 類型,我們可以傳入這 4 種類型中的任意一個。 eg 傳一個 int 類型:
max[int32](1, 2) // 2
也支持傳一個 float32 類型:
max[float32](0.1, 0.2) // 0.2
max 函數(shù)提供類型參數(shù)(在本例中為 int 和float32 ) 稱為實例化。eg:
// 類型實例化,編譯器生成 T=float32 的 max 函數(shù) f := max[float32] fmt.Println(f(0.1, 0.2))
我們定義了一個 max[float32]
函數(shù) f
,我們可以在接下來調用函數(shù)的方式使用 f(0.1, 0.2)
它 。
類型約束
類型約束是指限制類型參數(shù)的類型的約束條件,可以使用interface關鍵字來表示。以上方的 demo,我們常見的方式有:
類型約束接口直接在類型參數(shù)列表中使用:
func max[T interface{ int | int32 | int64 | float32 }](x, y T) T { if x >= y { return x } return y }
也可以事先定義,后復用
// 事先定義類型約束類型 type Value interface { int | int32 | int64 | float32 } func min[T Value](a, b T) T { if a <= b { return a } return b }
在定義一個可以比較大小的泛型函數(shù)時,可以使用 comparable
約束條件來限制類型參數(shù)的類型:
func MapKeys[K comparable, V any](m map[K]V) []K { r := make([]K, 0, len(m)) for k := range m { r = append(r, k) } return r }
類型集
類型集是泛型語法中用來約束類型參數(shù)的工具,它規(guī)定了類型參數(shù)所能接受的類型范圍。在 Golang 1.18 中,類型集使用 interface 來定義,在類型參數(shù)后面添加 interface 關鍵字來實現(xiàn)的。通俗一點解釋,接口類型現(xiàn)在可以用作值的類型,也可以用作類型約束。
下面是一個定義了類型集的例子:
type MySlice interface { int | float32 | string }
上面這個就表示定義了一個 int、float32、string 的類型集。
any 接口
Go 在 1.18 引入了一個新的預聲明標識符,作為空接口類型的別名。
type any = interface{}
使用 eg:
func Swap[T any](a, b *T) { temp := *a *a = *b *b = temp }
類型推斷
最后說下類型推斷,非常重要,在go 1.18 后推出,能夠讓開發(fā)者在使用泛型時更加的自然。
參數(shù)類型推斷
對于函數(shù)參數(shù)的類型,需要傳遞類型參數(shù),使得代碼變長??聪乱婚_始的 demo
func max[T int | int32 | int64 | float32](x, y T) T { if x >= y { return x } return y }
調用
var a, b, s int a := 1 b := 2 s := max[int32](a, b) // 2
在大部分場景下,我們的編譯器其實可以自行推斷類型參數(shù) T
。有了這個可以似的我們的代碼變的更短,同事保持清晰。
var a, b, s int a := 1 b := 2 s := max(a, b) // 2
總結
Go 在 1.18 中引入了泛型這一特性,極大地增強了語言的表現(xiàn)力和靈活性。通過類型參數(shù)、類型集、類型推斷等語法特性,可以方便地定義和使用泛型類型和泛型函數(shù)。同時,編譯器對泛型的支持也在不斷完善,包括對類型參數(shù)的約束、類型集的多態(tài)和類型推斷的增強等,進一步提升了泛型的實用性和性能。
在實際開發(fā)中,泛型可以用來處理許多常見的問題,如集合類的封裝、算法的實現(xiàn)和通用接口的定義等。除了標準庫中已經實現(xiàn)的泛型類型和函數(shù)之外,我們還可以通過自定義泛型類型和函數(shù)來滿足特定的需求。
最后,使用泛型時需要注意類型安全和性能問題,特別是對于大規(guī)模的數(shù)據(jù)處理和算法計算,需要進行細致的測試和優(yōu)化。
到此這篇關于Golang中的泛型你真的了解嗎的文章就介紹到這了,更多相關Golang泛型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Go語言for range(按照鍵值循環(huán))遍歷操作
這篇文章主要介紹了Go語言for range(按照鍵值循環(huán))遍歷操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12Go語言基于viper實現(xiàn)apollo多實例快速
viper是適用于go應用程序的配置解決方案,這款配置管理神器,支持多種類型、開箱即用、極易上手。本文主要介紹了如何基于viper實現(xiàn)apollo多實例快速接入,感興趣的可以了解一下2023-01-01golang解析json數(shù)據(jù)的4種方法總結
在日常工作中每一名開發(fā)者,不管是前端還是后端,都經常使用 JSON,下面這篇文章主要給大家介紹了關于golang解析json數(shù)據(jù)的4種方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06