欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

golang中的泛型是什么及怎么使用

本篇內(nèi)容介紹了“golang中的泛型是什么及怎么使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

公司主營業(yè)務:網(wǎng)站建設、成都網(wǎng)站建設、移動網(wǎng)站開發(fā)等業(yè)務。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。成都創(chuàng)新互聯(lián)是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。成都創(chuàng)新互聯(lián)推出青白江免費做網(wǎng)站回饋大家。

什么是泛型

泛型(Generic)是一種編程技術。在強類型語言中, 允許編寫代碼時使用以后才指定的類型, 在實例化時指定對應的類型。

在泛型中,可以使用類型參數(shù)來代替具體的數(shù)據(jù)類型。這些類型參數(shù)可以在類、方法或接口中聲明,并且可以在這些聲明中使用。使用泛型的代碼可以在運行時指定實際的類型參數(shù), 這使得代碼可以適用于多種不同類型的數(shù)據(jù)。

泛型可以提高代碼的可讀性、可維護性和可重用性。它可以減少代碼的冗余程度, 并且可以提供更好的類型安全性和編譯時類型檢查。

我們通過一個具體的例子來解釋一下為什么泛型可以減少代碼的冗余:

提供一個函數(shù), 返回 a, b 的最小值, 我們需要每一種特定的數(shù)據(jù)類型「int, float...」寫一個函數(shù); 或者使用 interface{}「需要對參數(shù)進行類型斷言, 對運行性能有影響, 且無法約束傳入的參數(shù)」

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

func minFloat(a, b float64) float64 {
    if a > b {
        return b
    }
    return a
}

func minItf(a, b interface{}) interface{} {
    switch a.(type) {
    case int:
        switch b.(type) {
        case int:
            if a.(int) > b.(int) {
                return b
            }
            return a
        }
    case float64:
        switch b.(type) {
        case float64:
            if a.(float64) > b.(float64) {
                return b
            }
            return a
        }
    }
    return nil
}

從上面的方法我們可以看出, minInt 和 minFloat 除了參數(shù)與返回結(jié)果的類型不同之外, 其余代碼均相同。那有沒有一種方式可以不指定特定的類型, 在函數(shù)調(diào)用的時候再確定傳入的類型?這里就引入一個概念叫泛型, 可以簡單理解為寬泛的類型或者未指定具體類型。通過引入泛型, 我們就無需再指定具體的數(shù)據(jù)類型, min 函數(shù)就可以使用下面的方式:

// T 為類型參數(shù), 在調(diào)用時確定參數(shù)的具體值, 可以為 int, 也可以為 float64;它與 a, b 一樣也是參數(shù), 需要調(diào)用時傳入具體的值;不同的是,T 為類型參數(shù),值為具體的類型, a,b 為函數(shù)參數(shù),值為具體類型對應的值
func minIntAndFloat64[T int | float64](a, b T) T { 
    if a < b {
        return a
    }
    return b
}

minIntAndFloat64[int](1, 2) // 實例化/調(diào)用時指定具體的類型

go 中的泛型

go 在 1.8 版本中才引入了泛型。如果你的 go 版本低于 1.8, 那是無法使用泛型的。本文中的代碼使用的版本為 1.9。在 1.8 版本中, 為支持泛型, 做了大量的改動。

  • 在函數(shù)和類型聲明中引入了類型參數(shù)

  • 可以通過接口定義類型的集合, 包括沒有方法的類型

  • 類型推導, 部分場景中會對類型參數(shù)進行推導, 可以在調(diào)用函數(shù)時不指定類型參數(shù)的值

形參、實參、類型參數(shù)、類型實參、實例化

先看一個普通的 add 函數(shù)。add 為函數(shù)名, x, y 為形參, (x,y int)為參數(shù)列表。發(fā)生函數(shù)調(diào)用時, add(2, 3) 2, 3 為實參。

golang中的泛型是什么及怎么使用類比到泛型中, 我們需要一個類型參數(shù), 當發(fā)生函數(shù)調(diào)用時傳入對應的類型實參, 帶有類型參數(shù)的函數(shù)叫做泛型函數(shù)。[T int | int64] 為類型參數(shù)列表, T 為類型參數(shù), int | int64 為類型集合/類型約束。當發(fā)生函數(shù)調(diào)用時 add[int](2,3),int 即為類型實參, 這一調(diào)用我們也叫做實例化, 即確定類型實參。

golang中的泛型是什么及怎么使用

在結(jié)構(gòu)體聲明時, 也可以指定類型參數(shù)。MyStruct[T] 是一個泛型結(jié)構(gòu)體, 可以為泛型結(jié)構(gòu)體定義方法。

golang中的泛型是什么及怎么使用

類型集合、接口

在基礎類型中, uint8 表示 0~255 的集合。那么對于類型參數(shù), 也需要像基礎類型一樣, 定義類型的集合。在上面的例子中 int | string就是類型的集合。那么如何對類型的集合進行復用呢?這里就使用了接口來進行定義。下面就是一個類型集合的定義。因此, 我們可以定義一個泛型函數(shù) add[T Signed](x, y T) T

golang中的泛型是什么及怎么使用

在 go 1.8 之前, 接口的定義是方法的集合, 即實現(xiàn)了接口對應的方法, 就可以轉(zhuǎn)換為對應的接口。在下面的例子中, MyInt 類型實現(xiàn)了 Add 方法, 因此可以轉(zhuǎn)換為 MyInterface

type MyInterface interface {
    Add(x, y int) int
}

type MyInt int

func (mi myInt) Add(x, y int) int {
    return x + y
}

func main() {
    var mi MyInterface = myInt(1)
    fmt.Println(mi.Add(1, 2))
}

如果我們換個角度來思考一下, MyInterface 可以看作一個類型集合, 即包含了所有實現(xiàn) add 方法的類型。 那么, MyInterface 就可以作為類型集合使用。例如, 我們可以定義如下泛型函數(shù)。

func I[T MyInterface](x, y int, i T) int {
    return i.Add(x, y)
}

在泛型中, 我們的類型集合不僅僅是實現(xiàn)接口中定義方法的類型, 還需要包含基礎的類型。因此, 我們可以對接口的定義進行延伸, 使其支持基礎類型。為了保證向前兼容, 我們需要對接口類型進行分類:

基礎接口類型

只包含方法的集合, 既可以當作類型集合, 又可以作為數(shù)據(jù)類型進行聲明。如下面的 MyInterface。還有一個特殊的接口類型 interface{}, 它可以用來表示任意類型, 即所有的類型都實現(xiàn)了它的空方法。在 1.8 之后可以使用 any 進行聲明。

type any = interface{}

type MyInterface interface {
    Add(x, y int) int
    String() string
    String() string  // 非法: String 不能重復聲明
    _(x int)         // 非法: 必須要有一個非空的名字
}
接口組合

可以通過接口組合的形式聲明新的接口, 從而盡可能的復用接口。從下面的例子可以看出, ReadWriterReaderWrite 的類型集合的交集。

type Reader interface {
        Read(p []byte) (n int, err error)
        Close() error
}

type Writer interface {
        Write(p []byte) (n int, err error)
        Close() error
}

// ReadWriter's methods are Read, Write, and Close.
type ReadWriter interface {
        Reader  // includes methods of Reader in ReadWriter's method set
        Writer  // includes methods of Writer in ReadWriter's method set
}
通用接口

上面說的接口都必須要實現(xiàn)具體的方法, 但是類型集合中無法包含基礎的數(shù)據(jù)類型。如: int, float, string...。通過下面的定義, 可以用來表示包含基礎數(shù)據(jù)類型的類型集合。在 golang.org/x/exp/constraints 中定義了基礎數(shù)據(jù)類型的集合。我們可以看到 符號, 它表示包含潛在類型為 int | int8 | int16 | int32 | int64 的類型, | 表示取并集。Singed 就表示所有類型為 int 的類型集合。

// Signed is a constraint that permits any signed integer type.
// If future releases of Go add new predeclared signed integer types,
// this constraint will be modified to include them.
type Signed interface {
     ~int | ~int8 | ~int16 | ~int32 | ~int64
}

type myInt int // 潛在類型為 int

func add[T constraints.Integer](x, y T) T {
        return x + y
}

func main() {
        var x, y myInt = 1, 2
        fmt.Println(add[myInt](x, y))
}

下面來看一些特殊的定義

// 潛在類型為 int, 并且實現(xiàn)了 String 方法的類型
type E interface {
    ~int
    String() string
}

type mInt int // 屬于 E 的類型集合
func (m mInt) String() string {
    return fmt.Sprintf("%v", m)
}

// 潛在類型必須是自己真實的類型
type F interface {
    ~int
    // ~mInt  invalid use of ~ (underlying type of mInt is int)
    // ~error illegal: error is an interface
}

// 基礎接口可以作為形參和類型參數(shù)類型, 通用類型只能作為類型參數(shù)類型, E 只能出現(xiàn)在類型參數(shù)中 [T E]
var x E                    // illegal: cannot use type E outside a type constraint: interface contains type constraints
var x interface{} = E(nil) // illegal: cannot use interface E in conversion (contains specific type constraints or is comparable)

類型推導

由于泛型使用了類型參數(shù), 因此在實例化泛型時我們需要指定類型實參。 看下面的 case, 我們在調(diào)用函數(shù)的時候并沒有指定類型實參, 這里是編譯器進行了類型推導, 推導出類型實參, 不需要顯性的傳入。

func add[T constraints.Integer](x, y T) T {
    return x + y
}

func main() {
    fmt.Println(add(1, 1)) // add[int](1,1)
}

有時候, 編譯器無法推導出具體類型。則需要指定類型, 或者更換寫法, 也許可以推斷出具體類型。

// 將切片中的值擴大
func Scale[E constraints.Integer](s []E, c E) []E {
    r := make([]E, len(s))
    for i, v := range s {
        r[i] = v * c
    }
    return r
}

func ScaleAndPrint(p Point) {
    r := Scale(p, 2)
    r.string() // 非法, Scale 返回的是 []int32
}

type Point []int32

func (p Point) string() {
    fmt.Println(p)
}

// 方法更新,這樣傳入的是 Point 返回的也是 Point
func Scale[T ~[]E, E constraints.Integer](s T, c E) T {
    r := make([]E, len(s))
    for i, v := range s {
        r[i] = v * c
    }
    return r
}

泛型的使用

go 是在 1.8 版本中開始引入泛型的。下面主要介紹一下什么時候使用泛型:

內(nèi)置容器類型

在 go 中, 提供以下容器類型:map, slice, channel。當我們用到容器類型時, 且邏輯與容器具體的類型無關, 這個時候可以考慮泛型。這樣我們可以在調(diào)用時指定具體的類型實參, 從而避免了類型斷言。例如,下面的例子, 返回 map 中的 key。

// comparable 是一個內(nèi)置類型, 只能用于對類型參數(shù)的約束。在 map 中, key 必須是可比較類型。
func GetKeys[K comparable, V any](m map[K]V) []K {
    res := make([]K, 0, len(m))
    for k := range m {
        res = append(res, k)
    }
    return res
}

通用的結(jié)構(gòu)體

對于一些通用的結(jié)構(gòu)體, 我們應該使用泛型。例如, 棧、隊列、樹結(jié)構(gòu)。這些都是比較通用的結(jié)構(gòu)體, 且邏輯都與具體的類型無關, 因此需要使用泛型。下面是一個棧的例子:

type Stack[T any] []T

func (s *Stack[T]) Push(item T) {
    *s = append(*s, item)
}

func (s *Stack[T]) Pop() T {
    if len(*s) == 0 {
        panic("can not pop item in emply stack")
    }
    lastIndex := len(*s) - 1
    item := (*s)[lastIndex]
    *s = (*s)[:lastIndex]
    return item
}

func main() {
    var s Stack[int]
    s.Push(9)
    fmt.Println(s.Pop())
    s.Push(9)
    s.Push(8)
    fmt.Println(s.Pop(), s.Pop())
}

通用的函數(shù)

有些類型會實現(xiàn)相同的方法, 但是對于這些類型的處理邏輯又與具體類型的實現(xiàn)無關。例如: 兩個數(shù)比大小, 只要實現(xiàn) Ordered 接口即可進行大小比較:

func Min[T constraints.Ordered](x, y T) T {
    if x < y {
        return x
    }

    return y
}

func main() {
    fmt.Println(Min(5, 6))
    fmt.Println(Min(6.6, 9.9))
}

“golang中的泛型是什么及怎么使用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

本文標題:golang中的泛型是什么及怎么使用
當前URL:http://www.chinadenli.net/article12/gccpdc.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供外貿(mào)網(wǎng)站建設網(wǎng)站營銷網(wǎng)站導航用戶體驗虛擬主機軟件開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名