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






































