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