golang1.21泛型函數(shù)全面講解
Go 1.21中的泛型基本語法
要定義泛型函數(shù)或類型,可以使用類型 T
關(guān)鍵字,后跟用方括號[]括起來的泛型形參的名稱。例如,要創(chuàng)建一個接受任意類型的slice并返回其第一個元素的泛型函數(shù),可以這樣定義:
func First[T any](items []T) T { return items[0] }
在上面的例子中,[T any]
表示類型參數(shù)T
,它表示任意類型。any
關(guān)鍵字表示T類型可以是任何有效類型。
然后,可以使用任何切片類型調(diào)用First
函數(shù),該函數(shù)將返回該切片的第一個元素。例如:
func func1() { intSlice := []int{1, 2, 3, 4, 5} firstInt := First[int](intSlice) // returns 1 println(firstInt) stringSlice := []string{"apple", "banana", "cherry"} firstString := First[string](stringSlice) // returns "apple" println(firstString) } func First[T any](items []T) T { return items[0] }
注意,在調(diào)用泛型函數(shù)時,我們在方括號[]
中指定類型參數(shù)。這允許編譯器在編譯期間為該類型生成特定的代碼。
我們還可以向泛型類型參數(shù)添加約束,將其限制為特定類型。例如,如果我們想將類型T
限制為僅實現(xiàn)Stringer
接口的類型,可以使用如下約束:
func PrintString[T Stringer](value T) { fmt.Println(value.String()) }
Stringer
約束確保類型T
必須具有String()
方法。這個約束允許我們在函數(shù)的value
參數(shù)上安全地調(diào)用String()
方法。
在Go 1.21中具有各種類型的泛型
在另一個示例中,讓我們編寫函數(shù)SumGenerics
,它對各種數(shù)字類型(如int
、int16
、int32
、int64
、int8
、float32
和float64
)執(zhí)行加法操作。
func SumGenerics[T int | int16 | int32 | int64 | int8 | float32 | float64](a, b T) T { return a + b }
讓我們看看如何利用這個泛型函數(shù):
func func2() { sumInt := SumGenerics[int](2, 3) sumFloat := SumGenerics[float32](2.5, 3.5) sumInt64 := SumGenerics[int64](10, 20) fmt.Println(sumInt) // returns 5 fmt.Println(sumFloat) // returns 6.0 fmt.Println(sumInt64) // returns 30 }
在上面的代碼中,我們可以看到,通過在調(diào)用泛型函數(shù)時在方括號[]
中指定類型參數(shù),我們可以對不同的數(shù)字類型執(zhí)行加法操作。類型約束確保只有指定的類型[T int, int16, int32, int64, int8, float32,或float64]
可以用作類型參數(shù)。
以這種方式使用泛型使我們能夠在不犧牲類型安全的情況下編寫簡潔且可重用的代碼??梢允褂酶鞣N數(shù)字類型調(diào)用該函數(shù),編譯器將為每種類型生成特定的代碼,以確保正確執(zhí)行加法操作。
Go 1.21中具有任意數(shù)據(jù)類型的泛型
泛型可以用于任意數(shù)據(jù)類型的序列化和反序列化,使用提供的序列化和反序列化函數(shù):
type Person struct { Name string Age int Address string } func Serialize[T any](data T) ([]byte, error) { buffer := bytes.Buffer{} encoder := gob.NewEncoder(&buffer) err := encoder.Encode(data) if err != nil { return nil, err } return buffer.Bytes(), nil } func Deserialize[T any](b []byte) (T, error) { buffer := bytes.Buffer{} buffer.Write(b) decoder := gob.NewDecoder(&buffer) var data T err := decoder.Decode(&data) if err != nil { return data, err } return data, nil }
在本例中,我們有兩個通用函數(shù)Serialize
和Deserialize
,它們利用Go的gob
包將任意數(shù)據(jù)類型轉(zhuǎn)換為字節(jié),反之亦然。
func DeserializeUsage() { person := Person{ Name: "John", Age: 30, Address: "123 Main St.", } serialized, err := Serialize(person) if err != nil { panic(err) } deserialized, err := Deserialize[Person](serialized) if err != nil { panic(err) } fmt.Printf("Name: %s, Age: %d, Address: %s", deserialized.Name, deserialized.Age, deserialized.Address) }
Output: Name: John, Age: 30, Address: 123 Main St.
在上面的代碼中,我們用一些數(shù)據(jù)創(chuàng)建了一個Person
實例。然后使用Serialize
函數(shù)將person
對象轉(zhuǎn)換為字節(jié)數(shù)組。稍后,使用Deserialize
函數(shù),將字節(jié)數(shù)組轉(zhuǎn)換回Person
對象。
通過將序列化和反序列化函數(shù)定義為具有T any
類型參數(shù)的泛型函數(shù),我們可以序列化和反序列化任何支持使用gob
包進行編碼和解碼的數(shù)據(jù)類型。
在Go中使用泛型和Validate函數(shù)自定義驗證器
讓我們用自定義驗證器編寫一個通用的Validate
函數(shù)。
type Validator[T any] func(T) error func Validate[T any](data T, validators ...Validator[T]) error { for _, validator := range validators { err := validator(data) if err != nil { return err } } return nil }
在本例中,我們有一個通用的Validate
函數(shù),它使用自定義驗證器執(zhí)行數(shù)據(jù)驗證。Validator
類型表示一個函數(shù),它接受任意類型T
的值并返回一個錯誤。
func StringNotEmpty(s string) error { if len(strings.TrimSpace(s)) == 0 { return fmt.Errorf("string cannot be empty") } return nil } func IntInRange(num int, min, max int) error { if num < min || num > max { return fmt.Errorf("number must be between %d and %d", min, max) } return nil }
此外,我們有兩個自定義驗證器示例:StringNotEmpty
和IntInRange
。
StringNotEmpty
確保字符串不為空,IntInRange
檢查整數(shù)是否在指定范圍內(nèi)。
package main func main() { person := Person{ Name: "John", Age: 30, Address: "123 Main St.", } err := Validate(person, func(p Person) error { return StringNotEmpty(p.Name) }, func(p Person) error { return IntInRange(p.Age, 0, 120) }) if err != nil { println(err.Error()) panic(err) } println("Person is valid") }
在本例中,我們創(chuàng)建了一個Person
實例,并將其傳遞給Validate
函數(shù)。我們?yōu)?code>Person結(jié)構(gòu)定義了兩個自定義驗證器,檢查Name
字段是否為空,Age
字段是否在有效范圍內(nèi)。如果任何驗證器返回錯誤,驗證過程將停止,并返回相應(yīng)的錯誤。
通過使用泛型和自定義驗證器,Validate
函數(shù)允許跨不同數(shù)據(jù)類型進行靈活和可重用的數(shù)據(jù)驗證,增強代碼可重用性,并使添加或修改驗證規(guī)則變得容易。
讓我們再寫一個使用validator函數(shù)的例子
type LoginForm struct { Username string Password string } func (f *LoginForm) Validate() error { return Validate(f, func(l *LoginForm) error { return StringNotEmpty(l.Username) }, func(l *LoginForm) error { return StringNotEmpty(l.Password) }, ) } func ValidateUsage2() { loginForm := LoginForm{ Username: "John", Password: "123", } err := loginForm.Validate() if err != nil { println(err.Error()) panic(err) } println("Login form is valid") }
在本例中,LoginForm
結(jié)構(gòu)實現(xiàn)了一個Validate
方法,該方法利用了我們之前定義的Validate
泛型函數(shù)。
Validate
方法調(diào)用通用的Validate
函數(shù),并為它提供兩個特定于LoginForm
類型的自定義驗證器。驗證器表示為閉包函數(shù),使用StringNotEmpty
驗證器函數(shù)檢查Username
和Password
字段是否為空。
要驗證LoginForm
實例,只需在實例本身上調(diào)用validate
方法。
package main func main() { loginForm := LoginForm{ Username: "John", Password: "123", } err := loginForm.Validate() if err != nil { println(err.Error()) panic(err) } println("Login form is valid") }
如果任何驗證器返回錯誤,驗證過程將停止,并返回相應(yīng)的錯誤。在這種情況下,我們相應(yīng)地處理錯誤。
總結(jié)
這些示例展示了Go 1.21中泛型的強大功能和多功能性。泛型使我們能夠編寫可重用和類型安全的代碼,這些代碼可以處理不同的數(shù)據(jù)類型和結(jié)構(gòu),而不會犧牲代碼的清晰度和可維護性。
泛型為Go編程語言帶來了顯著的好處,增強了代碼重用,減少了冗余,并改進了代碼組織。有了泛型,開發(fā)人員就能夠編寫更有表現(xiàn)力、更簡潔、更靈活的代碼,以適應(yīng)不同的數(shù)據(jù)類型和結(jié)構(gòu),從而為更具可擴展性和可維護性的軟件開發(fā)鋪平道路。
以上就是golang1.21泛型函數(shù)全面講解的詳細內(nèi)容,更多關(guān)于go1.21泛型函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
golang操作elasticsearch的實現(xiàn)
這篇文章主要介紹了golang操作elasticsearch,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06golang使用json格式實現(xiàn)增刪查改的實現(xiàn)示例
這篇文章主要介紹了golang使用json格式實現(xiàn)增刪查改的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05golang獲取prometheus數(shù)據(jù)(prometheus/client_golang包)
本文主要介紹了使用Go語言的prometheus/client_golang包來獲取Prometheus監(jiān)控數(shù)據(jù),具有一定的參考價值,感興趣的可以了解一下2025-03-03