Golang泛型的使用方法詳解
Go 和Python語言不同,處理不同數(shù)據(jù)類型非常嚴(yán)格。如Python可以定義函數(shù)帶兩個(gè)數(shù)值類型并返回較大的數(shù)值,但可以不嚴(yán)格指定參數(shù)類型為float或integer。同樣功能go1.18之前版本需要定義兩個(gè)函數(shù)分別處理對應(yīng)類型,通過泛型可以實(shí)現(xiàn)上面描述功能,無需為每種類型重復(fù)定義函數(shù)。
本文通過示例學(xué)習(xí)Go泛型,包括三個(gè)部分:非泛型函數(shù),泛型函數(shù),泛型類型約束。
泛型的作用
我們知道Go一些函數(shù)(如fmt.Println)使用空interface支持多種數(shù)據(jù)類型,但需要開發(fā)者寫大量代碼實(shí)現(xiàn)很多函數(shù)或方法支持多種自定義類型不是最佳選項(xiàng),于是泛型登場,提供新的解決方案,無需使用接口和反射支持多種數(shù)據(jù)類型。
下面通過示例來說明:
package main import ( "fmt" ) func Print[T any](s []T) { for _, v := range s { fmt.Print(v, " ") } fmt.Println() } func main() { Ints := []int{1, 2, 3} Strings := []string{"One", "Two", "Three"} Print(Ints) Print(Strings) }
上面代碼種Print()函數(shù)使用泛型,通過在函數(shù)名稱和參數(shù)之間增加[T any]
指定泛型變量, 既然T 為any類型,函數(shù)可傳入任何數(shù)據(jù)類型slice。當(dāng)然Print函數(shù)不能處理slice之外的輸入,這是因?yàn)楹瘮?shù)實(shí)現(xiàn)決定的。通過泛型函數(shù)可以避免針對每種數(shù)據(jù)類型編寫函數(shù),這種通用的思想就是泛型。
非泛型函數(shù)
我們實(shí)現(xiàn)兩個(gè)函數(shù),返回?cái)?shù)值類型數(shù)組元素的和。我們至少創(chuàng)建兩個(gè)函數(shù),一個(gè)針對float64類型,另一個(gè)為int64,因此工作量翻倍。
package main import "fmt" func main() { f := []float64{1.0, 2.0, 3.0, 4.0, 5.0} i := []int64{1, 2, 3, 4, 5} s1 := SumOfFloat(f) s2 := SumOfIntegers(i) fmt.Println("Sum for float64 :", s1) fmt.Println("Sum for int64 :", s2) } func SumOfFloat(nums []float64) float64 { var sum float64 for _, num := range nums { sum += num } return sum } func SumOfIntegers(nums []int64) int64 { var sum int64 for _, num := range nums { sum += num } return sum }
運(yùn)行輸出結(jié)果:
$ go run main.go
Sum for float64 : 15
Sum for int64 : 15
上面代碼針對兩種類型定義了兩個(gè)函數(shù),返回各自參數(shù)對應(yīng)類型數(shù)組元素之和。下面通過泛型合并兩個(gè)函數(shù)為一個(gè),節(jié)約時(shí)間和精力。
泛型函數(shù)
本節(jié)實(shí)現(xiàn)單個(gè)函數(shù),參數(shù)仍然是數(shù)組,但類型可以為float64或int64,并返回?cái)?shù)組元素之和,從而可以代替上面兩個(gè)函數(shù)。
為了能夠定義函數(shù)接收float64和int64兩種類型,新的泛型函數(shù)需要聲明接收的類型,即調(diào)用代碼需要判斷類型是否為float64或int64。為此,新的函數(shù)簽名需要有點(diǎn)變化,除了普通的參數(shù)外,還需要聲明類型參數(shù),從而轉(zhuǎn)換函數(shù)為泛型函數(shù)支持不同類型。
每個(gè)形參都有一個(gè)類型約束,它指定調(diào)用代碼可用于形參允許的實(shí)參類型。在編譯時(shí)這些參數(shù)表示的類型就是調(diào)用代碼支持的類型。當(dāng)然泛型函數(shù)的實(shí)現(xiàn)邏輯需要支持形參聲明的所有類型。舉例,泛型函數(shù)支持字符串和數(shù)值參數(shù),函數(shù)實(shí)現(xiàn)邏輯需要對參數(shù)進(jìn)行索引,顯然數(shù)值無法索引將引起編譯錯(cuò)誤。
泛型函數(shù)語法:
func genericFunction[T any](s []T) []T{
}
解釋如下:
上面語法種在名稱和參數(shù)之間的[]
用于指定形式參數(shù)類型,可以是一組類型或一個(gè)約束接口。T
參數(shù)類型,用于定義形式參數(shù)和返回值類型。
函數(shù)內(nèi)部也可以訪問參數(shù),any
是一個(gè)interface
,T
必須實(shí)現(xiàn)該接口。Go1.18版本引入any
,底層引用空接口,即interface{}
。 下面舉例說明:
package main import "fmt" func main() { f := []float64{1.0, 2.0, 3.0, 4.0, 5.0} i := []int64{1, 2, 3, 4, 5} s1 := genericSum(f) s2 := genericSum(i) fmt.Println("Sum for float64 :", s1) fmt.Println("Sum for int64 :", s2) } func genericSum[N int64 | float64](nums []N) N { var sum N for _, num := range nums { sum += num } return sum }
輸出結(jié)果:
$ go run main.go
Sum for float64 : 15
Sum for int64 : 15
上面示例中演示定義泛型函數(shù)genericSum。參數(shù)類型在[]中聲明的泛型類型。N聲明在形參和返回值中使用,N是新的類型,被限定了兩種類型float64 和 int64
的聯(lián)合類型。
在函數(shù)體類,首先聲明N類型變量,然后遍歷數(shù)組計(jì)算綜合并返回。
假設(shè)泛型函數(shù)支持很多種類型,比如:int, int8 , int26, int32, int64, float32, float64
。這樣函數(shù)簽名變得非常冗長難看,我們可以定義一個(gè)類型包括上述類型,本質(zhì)上就是把聯(lián)合類型遷移至函數(shù)聲明外面。
package main import "fmt" type Number interface { int64 | float64 } func main() { f := []float64{1.0, 2.0, 3.0, 4.0, 5.0} i := []int64{1, 2, 3, 4, 5} s1 := genericSum(f) s2 := genericSum(i) fmt.Println("Sum for float64 :", s1) fmt.Println("Sum for int64 :", s2) } func genericSum[N Number](nums []N) N { var sum N for _, num := range nums { sum += num } return sum }
總結(jié)
本文是關(guān)于Go泛型的,因?yàn)榉盒褪荊olang的新成員。通過對比帶泛型和不帶泛型的函數(shù),泛型可以很明顯地節(jié)省時(shí)間和精力。泛型不是接口的替代品,兩者被設(shè)計(jì)為一起工作,避免重復(fù)代碼,讓Go類型更安全、代碼更整潔。
到此這篇關(guān)于Golang泛型的使用方法詳解的文章就介紹到這了,更多相關(guān)Golang泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GO 使用Webhook 實(shí)現(xiàn)github 自動(dòng)化部署的方法
這篇文章主要介紹了GO 使用Webhook 實(shí)現(xiàn)github 自動(dòng)化部署的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05Go語言中使用 buffered channel 實(shí)現(xiàn)線程安全的 pool
這篇文章主要介紹了Go語言中使用 buffered channel 實(shí)現(xiàn)線程安全的 pool,因?yàn)镚o語言自帶的sync.Pool并不是很好用,所以自己實(shí)現(xiàn)了一線程安全的 pool,需要的朋友可以參考下2014-10-10