你還不體驗泛型嗎?
介紹
之前有看過官方發(fā)布的一些泛型文章,但是沒動手玩過。還有沒動手的嗎,那么最后一班車了。
不管學(xué)什么入門先從官網(wǎng)拿例子。
這段代碼很簡單,定義兩個函數(shù),計算對應(yīng)傳入的map值的和。
兩個函數(shù)最大的不同在于函數(shù)參數(shù)類型有所不同,一個map的值類型為int64,一個為float64,對應(yīng)返回參數(shù)也有所不同。
在沒有泛型的情況下,每種類型都不得不重新定義一個函數(shù)。
有人可能會說,上面的代碼你可以這樣寫在一個函數(shù)里,
你確定這真的好嗎?
泛型函數(shù)
但是,有了泛型之后,那就簡單多了。
上面這段代碼中,定義了一個新函數(shù)SumIntsOrFloats,該函數(shù)聲明兩個類型參數(shù) [K comparable, V int64 | float64]。其中K指定了類型必須為可比較(即可以用作比較符 == 和 !=)。
因為 go中規(guī)定map的key必須是可比較類型。比如,我們不能這樣聲明一個map。
所以這里的K就不能使用any關(guān)鍵字。
另一個V參數(shù)指定了一個約束,該約束由int64和float64組成,使用 | 指定了聯(lián)合類型。
所以函數(shù)中m參數(shù)為map[K]V類型,K,V即為參數(shù)類型指定的類型。
假如你傳入的map值的類型為其他類型。比如下面這種就不行了。
類型約束
上面看到的是我們在方法上對參數(shù)做一些約束。
當(dāng)然我們也可以直接聲明類型約束。
上面的代碼聲明了一個Number用做類型約束的接口類型。在接口里聲明int64和float64聯(lián)合類型。
在SumNumbers中如果約束類型為int64或者 float64,那么只需要使用Number類型約束即可,就不用每個不同函數(shù)寫 int64 | float64,達到代碼復(fù)用的效果。
但是如果我這樣,
我們把map中的值類型調(diào)整為自定義的otherInt64類型,otherInt64的基礎(chǔ)類型也是int64。但是,這段代碼編譯會報錯。
原因是 int64 約束會將其限制為只能是該類型,也就是只能是int64,不能是基于此類型定義的其他類型。
如果想使用otherInt64咋么辦,很簡單,只需要一個~符號,
使用帶~xxtype會將其限制為基礎(chǔ)類型為xxtype的所有類型。
應(yīng)用
以上只是簡單介紹了一下泛型的使用姿勢,那么哪些場景下可以使用泛型呢?
日常開發(fā)中,像slice、map、channel的一些處理函數(shù),可能邏輯相同但是類型不同導(dǎo)致copy多個不同函數(shù),這時候可以用泛型解決。比如,
還有一些行為方面的。例如go中的排序,通過泛型,不需要每一個結(jié)構(gòu)都實現(xiàn)(Len,Less,Swap)三個方法,而是抽象出依賴于三個方法的行為。最終實現(xiàn)排序只需要依賴定義的這個抽象就行了。
其他方面的應(yīng)用可以自行體驗。
總結(jié)
這篇文章主要帶你們體驗下泛型的基本使用,以及對應(yīng)的類型約束,最后還簡單實驗了兩個泛型的場景demo,感興趣的可以自行體驗。更多內(nèi)容,歡迎留言區(qū)域交流。
附錄
https://go.dev/doc/tutorial/generics
https://teivah.medium.com/when-to-use-generics-in-go-36d49c1aeda