2023年11月29日 星期三

Go 泛型的使用

自 Go 1.18 支援泛型也一段時間了,在此紀錄一下泛型的使用

基本用法

使用 [] 來定義泛型型別(Generic Type Parameters)。

例如以下程式碼, N 可以是 int、float32、float64

func foo[N int | float32 | float64](a, b N) {
	fmt.Printf("%v + %v = %v", a, b, a+b)
}

所以 foo(1.1, 2.1) 或是 foo(1, 2) 都可以正常執行。

定義泛型型別

以以上程式碼為例,可以改寫成

type IntOrFloat interface {
	int | float32 | float64
}

func foo[N IntOrFloat](a, b N) {
	fmt.Printf("%v + %v = %v", a, b, a+b)
}

事前先定義泛型型別 IntOrFloat ,事後其他 func 也能使用該泛型型別。

struct 內的泛型型別

要定義一個使用到泛型的 struct ,可以這樣寫

type foo[N comparable] struct {
	data N
}

要作為 func 參數的話:

func bar[N comparable](f foo[N]) {}
組合 struct

如果要組合的話,則:

type foo2[N comparable] struct {
	foo[N]
}
Struct Function

在 Struct 裡面的 function 是不能另外使用泛型的。

說得更好懂一點,在 Java 裡面,可以這樣使用泛型:

class Foo{
	public <T> void bar (T t){
		// ...
	}
}

但 go 就不能,即以下 code 是不行的:

type Foo struct{}

func (f *Foo) Bar[N comparable](n N) {}

Struct 裡面的 function 只能使用預先定義好的泛型,例如

type Foo [N comparable]struct{}

func (f *Foo) Bar(n N) {}

官方說明中有解釋原由。

type func 內的泛型型別

要定義一個使用到泛型的 func type ,可以這樣寫

type foo[N comparable] func(n N) 

func foo作為參數的話,則

func bar[N comparable](f foo[N]) {
	// do something...
}

這樣的話,要執行 bar 會如下::

bar(func(i int){})
bar(func(i int64){})
bar(func(s string){})
Interface Function

Interface 和 Struct 的 function 其實差不多:泛型必須定義在 Interface 上,而不能直接定義在 interface 的 function。

即得這樣寫

type Foo interface[N comparable]{
	Bar(n N)
}

不能這樣寫

type Foo interface{
	Bar[N comparable](n N)
}

沒有留言:

張貼留言