泛型 問題解決 一個計算sum的函數 func sum(slice []int) int { var res int for _, value := range slice { res += value } return res } 如果需要提供對int,float64,string三種數據類型 ...
泛型
問題解決
一個計算sum的函數
func sum(slice []int) int {
var res int
for _, value := range slice {
res += value
}
return res
}
如果需要提供對int,float64,string三種數據類型的求sum函數,那麼不使用泛型的情況下就需要單獨寫三個函數,此時就需要使用泛型這種概念,來避免重覆代碼出現
// 這裡中括弧中括起來的就是泛型的定義,將這三種數據類型定義為T泛型,同時使用T泛型來定義入參和返回值的數據類型
func Sum[T int | float64 | string](slice []T) T {
var res T
for _, value := range slice {
res += value
}
return res
}
// 這樣在調用函數的時候,只需要知道具體T泛型對應的是哪種數據類型,就可以確定入參和返回值的數據類型了
func main() {
slice01 := []int{1, 2, 3}
fmt.Printf("%d\n", Sum(slice01)) // 6
slice02 := []float64{1.2, 2.2, 3.2}
fmt.Printf("%.2f\n", Sum(slice02)) // 6.60
slice03 := []string{"Hello", " ", "world!"}
fmt.Printf("%s\n", Sum(slice03)) // Hello world!
}
泛型的使用
-
在函數傳參中使用泛型
同上一個例子相同,在函數聲明中定義泛型,然後將他利用於入參,返回值,以及函數的內部定義
func Demo01[T int | string](input T) {
fmt.Println(reflect.TypeOf(input))
}
func main() {
// 通過傳參來判斷泛型T具體的數據類型
// T:string
Demo01("我是string類型") // string
// T:int
Demo01(123) // int
}
-
泛型結構體
同樣,泛型也適用於結構體,在結構體聲明時定義泛型,既可以在結構體內部使用泛型來聲明值的類型
// 使用泛型T來讓生產日期的數據類型多樣化,可以是int也可以是string
type robots[T int | string] struct {
name string
yearOfProduction T
}
func Demo03() {
// 使用帶有泛型的結構體實例化對象的時候,要確定泛型T的具體類型
// T:string
myRobot01 := robots[string]{"robot01", "2023"}
// T:int
myRobot02 := robots[int]{"robot02", 2023}
fmt.Printf("%T : %T\n", myRobot01.name, myRobot01.yearOfProduction) // string : string
fmt.Println(myRobot01.name, " : ", myRobot01.yearOfProduction) // robot01 : 2023
fmt.Printf("%T : %T\n", myRobot02.name, myRobot02.yearOfProduction) // string : int
fmt.Println(myRobot02.name, " : ", myRobot02.yearOfProduction) // robot02 : 2023
}
-
給泛型添加方法
// 先聲明帶有泛型的切片slice[]
type Slice[T int | string | float64] []T
// 然後給這個切片添加方法
func (mySlice Slice[T]) Demo04() T {
var res T
for _, t := range mySlice {
res += t
}
return res
}
func main() {
// 再使用切片實例化對象時同樣需要先確定泛型T的具體類型
var slice01 Slice[int] = []int{1, 2, 3}
// 直接使用裡面的方法
fmt.Printf("%d\n", slice01.Demo04())
var slice02 Slice[float64] = []float64{1.2, 2.2, 3.2}
fmt.Printf("%.2f\n", slice02.Demo04())
var slice03 Slice[string] = []string{"Hello", " ", "world!"}
fmt.Printf("%s\n", slice03.Demo04())
}
- 自定義泛型類型
如果類型太多了怎麼辦呢?這時候我們就可以自定義泛型類型
// 聲明方式類似介面
type MyInt interface{
int | int8 | int16 | int32 | int64
}
// T的類型為聲明的MyInt
func GetMax[T MyInt](a,b T) T {
if a > b {
return a
}
return b
}
特殊的泛型
go里內置了兩個泛型類型:any和comparable
泛型類型 | 作用 |
---|---|
any | 表示go裡面所有的內置基本類型,等價於interface{} |
comparable | 表示go裡面所有內置的可以進行比較的類型 |
總結
總而言之,這些初級用法,可以使代碼變得非常的簡潔,降低代碼重覆,在下麵情景的時候非常適合使用泛型:當你需要針對不同類型書寫同樣的邏輯,使用泛型來簡化代碼是最好的