最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang1.21泛型函數(shù)全面講解

 更新時(shí)間:2023年09月04日 09:17:35   作者:洛天楓  
在Go編程語(yǔ)言中,泛型一直是一個(gè)備受期待的特性,隨著Go?1.21的發(fā)布,本文旨在提供Go?1.21中泛型的詳細(xì)探索,闡明它們的優(yōu)點(diǎn)、語(yǔ)法、實(shí)現(xiàn)和最佳實(shí)踐,希望對(duì)大家有所幫助

Go 1.21中的泛型基本語(yǔ)法

要定義泛型函數(shù)或類(lèi)型,可以使用類(lèi)型 T關(guān)鍵字,后跟用方括號(hào)[]括起來(lái)的泛型形參的名稱(chēng)。例如,要?jiǎng)?chuàng)建一個(gè)接受任意類(lèi)型的slice并返回其第一個(gè)元素的泛型函數(shù),可以這樣定義:

func First[T any](items []T) T {
    return items[0]
}

在上面的例子中,[T any]表示類(lèi)型參數(shù)T,它表示任意類(lèi)型。any關(guān)鍵字表示T類(lèi)型可以是任何有效類(lèi)型。

然后,可以使用任何切片類(lèi)型調(diào)用First函數(shù),該函數(shù)將返回該切片的第一個(gè)元素。例如:

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í),我們?cè)诜嚼ㄌ?hào)[]中指定類(lèi)型參數(shù)。這允許編譯器在編譯期間為該類(lèi)型生成特定的代碼。

我們還可以向泛型類(lèi)型參數(shù)添加約束,將其限制為特定類(lèi)型。例如,如果我們想將類(lèi)型T限制為僅實(shí)現(xiàn)Stringer接口的類(lèi)型,可以使用如下約束:

func PrintString[T Stringer](value T) {
    fmt.Println(value.String())
}

Stringer約束確保類(lèi)型T必須具有String()方法。這個(gè)約束允許我們?cè)诤瘮?shù)的value參數(shù)上安全地調(diào)用String()方法。

在Go 1.21中具有各種類(lèi)型的泛型

在另一個(gè)示例中,讓我們編寫(xiě)函數(shù)SumGenerics,它對(duì)各種數(shù)字類(lèi)型(如intint16、int32、int64int8、float32float64)執(zhí)行加法操作。

func SumGenerics[T int | int16 | int32 | int64 | int8 | float32 | float64](a, b T) T {
    return a + b
}

讓我們看看如何利用這個(gè)泛型函數(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
}

在上面的代碼中,我們可以看到,通過(guò)在調(diào)用泛型函數(shù)時(shí)在方括號(hào)[]中指定類(lèi)型參數(shù),我們可以對(duì)不同的數(shù)字類(lèi)型執(zhí)行加法操作。類(lèi)型約束確保只有指定的類(lèi)型[T int, int16, int32, int64, int8, float32,或float64]可以用作類(lèi)型參數(shù)。

以這種方式使用泛型使我們能夠在不犧牲類(lèi)型安全的情況下編寫(xiě)簡(jiǎn)潔且可重用的代碼??梢允褂酶鞣N數(shù)字類(lèi)型調(diào)用該函數(shù),編譯器將為每種類(lèi)型生成特定的代碼,以確保正確執(zhí)行加法操作。

Go 1.21中具有任意數(shù)據(jù)類(lèi)型的泛型

泛型可以用于任意數(shù)據(jù)類(lèi)型的序列化和反序列化,使用提供的序列化和反序列化函數(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
}

在本例中,我們有兩個(gè)通用函數(shù)SerializeDeserialize,它們利用Go的gob包將任意數(shù)據(jù)類(lèi)型轉(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)建了一個(gè)Person實(shí)例。然后使用Serialize函數(shù)將person對(duì)象轉(zhuǎn)換為字節(jié)數(shù)組。稍后,使用Deserialize函數(shù),將字節(jié)數(shù)組轉(zhuǎn)換回Person對(duì)象。

通過(guò)將序列化和反序列化函數(shù)定義為具有T any類(lèi)型參數(shù)的泛型函數(shù),我們可以序列化和反序列化任何支持使用gob包進(jìn)行編碼和解碼的數(shù)據(jù)類(lèi)型。

在Go中使用泛型和Validate函數(shù)自定義驗(yàn)證器

讓我們用自定義驗(yàn)證器編寫(xiě)一個(gè)通用的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
}

在本例中,我們有一個(gè)通用的Validate函數(shù),它使用自定義驗(yàn)證器執(zhí)行數(shù)據(jù)驗(yàn)證。Validator類(lèi)型表示一個(gè)函數(shù),它接受任意類(lèi)型T的值并返回一個(gè)錯(cuò)誤。

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
}

此外,我們有兩個(gè)自定義驗(yàn)證器示例:StringNotEmptyIntInRange

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)建了一個(gè)Person實(shí)例,并將其傳遞給Validate函數(shù)。我們?yōu)?code>Person結(jié)構(gòu)定義了兩個(gè)自定義驗(yàn)證器,檢查Name字段是否為空,Age字段是否在有效范圍內(nèi)。如果任何驗(yàn)證器返回錯(cuò)誤,驗(yàn)證過(guò)程將停止,并返回相應(yīng)的錯(cuò)誤。

通過(guò)使用泛型和自定義驗(yàn)證器,Validate函數(shù)允許跨不同數(shù)據(jù)類(lèi)型進(jìn)行靈活和可重用的數(shù)據(jù)驗(yàn)證,增強(qiáng)代碼可重用性,并使添加或修改驗(yàn)證規(guī)則變得容易。

讓我們?cè)賹?xiě)一個(gè)使用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)實(shí)現(xiàn)了一個(gè)Validate方法,該方法利用了我們之前定義的Validate泛型函數(shù)。

Validate方法調(diào)用通用的Validate函數(shù),并為它提供兩個(gè)特定于LoginForm類(lèi)型的自定義驗(yàn)證器。驗(yàn)證器表示為閉包函數(shù),使用StringNotEmpty驗(yàn)證器函數(shù)檢查UsernamePassword字段是否為空。

要驗(yàn)證LoginForm實(shí)例,只需在實(shí)例本身上調(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àn)證器返回錯(cuò)誤,驗(yàn)證過(guò)程將停止,并返回相應(yīng)的錯(cuò)誤。在這種情況下,我們相應(yīng)地處理錯(cuò)誤。

總結(jié)

這些示例展示了Go 1.21中泛型的強(qiáng)大功能和多功能性。泛型使我們能夠編寫(xiě)可重用和類(lèi)型安全的代碼,這些代碼可以處理不同的數(shù)據(jù)類(lèi)型和結(jié)構(gòu),而不會(huì)犧牲代碼的清晰度和可維護(hù)性。

泛型為Go編程語(yǔ)言帶來(lái)了顯著的好處,增強(qiáng)了代碼重用,減少了冗余,并改進(jìn)了代碼組織。有了泛型,開(kāi)發(fā)人員就能夠編寫(xiě)更有表現(xiàn)力、更簡(jiǎn)潔、更靈活的代碼,以適應(yīng)不同的數(shù)據(jù)類(lèi)型和結(jié)構(gòu),從而為更具可擴(kuò)展性和可維護(hù)性的軟件開(kāi)發(fā)鋪平道路。

以上就是golang1.21泛型函數(shù)全面講解的詳細(xì)內(nèi)容,更多關(guān)于go1.21泛型函數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語(yǔ)言用Gin實(shí)現(xiàn)圖書(shū)管理接口的實(shí)現(xiàn)示例

    Go語(yǔ)言用Gin實(shí)現(xiàn)圖書(shū)管理接口的實(shí)現(xiàn)示例

    本文主要介紹了Go語(yǔ)言用Gin實(shí)現(xiàn)圖書(shū)管理接口的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-08-08
  • 一文詳解Go語(yǔ)言中方法的指針接收者與值接收者

    一文詳解Go語(yǔ)言中方法的指針接收者與值接收者

    在 Go 語(yǔ)言里,方法是一種特殊的函數(shù),它與特定的類(lèi)型關(guān)聯(lián),方法可以使用值接收者或者指針接收者,理解這兩種接收者的區(qū)別和使用場(chǎng)景,對(duì)于編寫(xiě)高效、正確的 Go 代碼至關(guān)重要,本文將深入剖析指針接收者和值接收者的特點(diǎn),需要的朋友可以參考下
    2025-06-06
  • GoLang內(nèi)存泄漏原因排查詳解

    GoLang內(nèi)存泄漏原因排查詳解

    內(nèi)存溢出是指程序在申請(qǐng)內(nèi)存時(shí),沒(méi)有足夠的內(nèi)存空間供其使用,簡(jiǎn)單點(diǎn)說(shuō)就是你要求分配的內(nèi)存超出了系統(tǒng)能給你的,系統(tǒng)不能滿足需求,于是產(chǎn)生溢出出現(xiàn)out of memory異常
    2022-12-12
  • go語(yǔ)言中range用法

    go語(yǔ)言中range用法

    這篇文章主要介紹了go語(yǔ)言中range用法,實(shí)例分析了Go語(yǔ)言中range的功能及使用技巧,需要的朋友可以參考下
    2015-03-03
  • Go語(yǔ)言的GOPATH與工作目錄詳解

    Go語(yǔ)言的GOPATH與工作目錄詳解

    這篇文章主要介紹了Go語(yǔ)言的GOPATH與工作目錄詳解,本文詳細(xì)講解了GOPATH設(shè)置、應(yīng)用目錄結(jié)構(gòu)、編譯應(yīng)用等內(nèi)容,需要的朋友可以參考下
    2014-10-10
  • Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用介紹

    Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用介紹

    這篇文章主要介紹了Golang回調(diào)函數(shù)與閉包和接口函數(shù)的定義及使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-05-05
  • Go語(yǔ)言使用字符串的幾個(gè)技巧分享

    Go語(yǔ)言使用字符串的幾個(gè)技巧分享

    這篇文章中小編將給出一些Go語(yǔ)言在處理字符串方面的技巧,對(duì)大家學(xué)習(xí)Go語(yǔ)言具有一定的參考借鑒價(jià)值,下面一起看看吧。
    2016-09-09
  • Golang?websocket協(xié)議使用淺析

    Golang?websocket協(xié)議使用淺析

    這篇文章主要介紹了Golang?websocket協(xié)議的使用,WebSocket是一種新型的網(wǎng)絡(luò)通信協(xié)議,可以在Web應(yīng)用程序中實(shí)現(xiàn)雙向通信,感興趣想要詳細(xì)了解可以參考下文
    2023-05-05
  • golang內(nèi)存逃逸的學(xué)習(xí)筆記

    golang內(nèi)存逃逸的學(xué)習(xí)筆記

    內(nèi)存逃逸是 Go 語(yǔ)言編程中一個(gè)特別需要注意的問(wèn)題,會(huì)影響到程序的性能和穩(wěn)定性,本文主要介紹了golang內(nèi)存逃逸的學(xué)習(xí)筆記,感興趣的可以了解一下
    2024-05-05
  • 詳解Go語(yǔ)言中接口應(yīng)用模式或慣例介紹

    詳解Go語(yǔ)言中接口應(yīng)用模式或慣例介紹

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中接口應(yīng)用模式或慣例介紹的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11

最新評(píng)論

梁山县| 出国| 常德市| 盐池县| 班玛县| 开阳县| 隆回县| 淅川县| 焉耆| 通山县| 明水县| 且末县| 英德市| 鄂伦春自治旗| 通河县| 石台县| 海原县| 德钦县| 砀山县| 东乡族自治县| 五大连池市| 焦作市| 屯门区| 抚远县| 柯坪县| 大田县| 靖州| 富阳市| 张家界市| 交城县| 明光市| 延安市| 舟山市| 井研县| 平昌县| 灌阳县| 临泽县| 玉门市| 西畴县| 阳曲县| 杭锦后旗|