首頁 > 軟體

Golang泛型的使用方法詳解

2022-06-17 14:01:59

1. 泛型是什麼

泛型生命週期只在編譯期,旨在為程式設計師生成程式碼,減少重複程式碼的編寫

在比較兩個數的大小時,沒有泛型的時候,僅僅只是傳入型別不一樣,我們就要再寫一份一模一樣的函數,如果有了泛型就可以減少這類程式碼

// int
func GetMaxNumInt(a, b int) int {
	if a > b {
		return a
	}

	return b
}

// int8
func GetMaxNumInt8(a, b int8) int8 {
	if a > b {
		return a
	}

	return b
}

2. 泛型的簡單使用

2.1. 泛型範例

需要go版本大於等於1.18

我們先改造一下上面的範例,只需要在函數後用中括號宣告T可能出現的型別,中間用符號"|" 分隔

// 使用泛型
func GetMaxNum[T int | int8](a, b T) T {
    if a > b {
        return a
    }

    return b
}

2.2. 自定義泛型型別

如果型別太多了怎麼辦呢?這時候我們就可以自定義泛型型別

// 像宣告介面一樣宣告
type MyInt interface {
	int | int8 | int16 | int32 | int64
}

// T的型別為宣告的MyInt
func GetMaxNum[T MyInt](a, b T) T {
	if a > b {
		return a
	}

	return b
}

2.3. 呼叫帶泛型的函數

如何呼叫這個帶有泛型的函數呢?

var a int = 10
var b int = 20

// 方法1,正常呼叫,編譯器會自動推斷出傳入型別是int
GetMaxNum(a, b)

// 方法2,顯式告訴函數傳入的型別是int
GetMaxNum[int](a, b)

3. 自定義泛型型別的語法

在2.2小節中我們可以看到一個泛型的簡單自定義型別,本節將會詳細描述泛型自定義型別的語法

3.1. 內建的泛型型別any和comparable

any: 表示go裡面所有的內建基本型別,等價於interface{}

comparable: 表示go裡面所有內建的可比較型別:int、uint、float、bool、struct、指標等一切可以比較的型別

3.2. 宣告一個自定義型別

跟宣告介面一樣,使用type x interface{} 關鍵字來宣告,不過裡面的成員不再是方法,而是型別,型別之間用符號 "|" 隔開

type MyInt interface {
    int | int8 | int16 | int32 | int64
}

成員型別支援go中所有的基本型別

type MyT interface {
    int | float32 | bool | chan int | map[int]int | [10]int | []int | struct{} | *http.Client
}

3.3. 泛型中的"~"符號是什麼

符號"~"都是與型別一起出現的,用來表示支援該型別的衍生型別

// int8的衍生型別
type int8A int8
type int8B = int8

// 不僅支援int8, 還支援int8的衍生型別int8A和int8B
type MyInt interface {
	~int8
}

4. 泛型的進階使用

4.1. 泛型與結構體

建立一個帶有泛型的結構體User,提供兩個獲取age和name的方法

注意:只有在結構體上宣告了泛型,結構體方法中才可以使用泛型

type AgeT interface {
	int8 | int16
}

type NameE interface {
	string
}

type User[T AgeT, E NameE] struct {
	age  T
	name E
}

// 獲取age
func (u *User[T, E]) GetAge() T {
	return u.age
}


// 獲取name
func (u *User[T, E]) GetName() E {
	return u.name
}

我們可以通過宣告結構體物件時,宣告泛型的型別來使用帶有泛型的結構體

// 宣告要使用的泛型的型別
var u User[int8, string]

// 賦值
u.age = 18
u.name = "weiwei"

// 呼叫方法
age := u.GetAge()
name := u.GetName()

// 輸出結果 18 weiwei
fmt.Println(age, name) 

5. 泛型的限制或缺陷

5.1 無法直接和switch配合使用

將泛型和switch配合使用時,無法通過編譯

func Get[T any]() T {
	var t T

	switch T {
	case int:
		t = 18
	}

	return t
}

只能先將泛型賦值給interface才可以和switch配合使用

func Get[T any]() T {
	var t T

	var ti interface{} = &t
	switch v := ti.(type) {
	case *int:
		*v = 18
	}

	return t
}

到此這篇關於Golang泛型的使用方法詳解的文章就介紹到這了,更多相關Golang泛型內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com