1.18版本开始,Go添加了对泛型的支持,即类型参数

一、泛型函数

如果我们要实现一个对int类型的求和函数

func add(a, b int) int {
  return a + b
}

但是这样写了之后,如果参数是float类型,int32类型这些,就没办法使用了。使用泛型进行问题解决

func add[T int | float64 | int32](a, b T) T {
  return a + b
}

二、泛型结构体

以下是一个返回泛型结构体案例

package main
import (
    "encoding/json"
    "fmt"
)

type Response[T any] struct {
    Code int    `json:"code"`
    Msg  string `json:"msg"`
    Data T      `json:"data"`
}

type User struct {
    Name string `json:"name"`
}

type UserInfo struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func main() {
    var userResponse Response[User]
    json.Unmarshal([]byte(`{"code":0,"msg":"成功","data":{"name":"大冬"}}`), &userResponse)
    fmt.Println(userResponse.Data.Name) // 大冬

    var userInfoResponse Response[UserInfo]
    json.Unmarshal([]byte(`{"code":0,"msg":"成功","data":{"name":"大冬","age":24}}`), &userInfoResponse)
    fmt.Println(userInfoResponse.Data.Name, userInfoResponse.Data.Age) // 大冬 24
}

三、泛型切片

泛型切片可以用于存储不同类型的元素。以下是一个示例:

package main
import "fmt"
func storeElements[T any](elements []T) {
    for _, element := range elements {
        // 可以对元素进行操作
        fmt.Println(element)
    }
}
func main() {
    intElements := []int{1, 2, 3}
    floatElements := []float64{4.5, 6.7, 8.9}
    stringElements := []string{"hello", "world"}
    storeElements(intElements)
    storeElements(floatElements)
    storeElements(stringElements)
}

四、泛型Map

泛型 Map 可以用于存储具有不同键值类型的映射。以下是一个示例:

package main
import "fmt"
// 定义一个泛型 Map
type GenericMap[K any, V any] map[K]V

func main() {
    // 创建一个 int 到 string 的泛型 Map
    intToStringMap := GenericMap[int, string]{
        1: "one",
        2: "two",
        3: "three",
    }
    // 访问和操作泛型 Map
    fmt.Println(intToStringMap[1]) // one
    intToStringMap[4] = "four"
    fmt.Println(intToStringMap) // map[1:one 2:two 3:three 4:four]
}

五、泛型联合类型

5.1 类型约束接口

type Integer int

type Number interface {
    int | int64 | float64 | float32
}

// 支持衍生类型的语法
type Number interface {
    ~int | int64 | float64 | float32
}
  • 这是一个 类型联合(union)接口,表示 T 只能是这四种数值类型之一。

  • 这是 Go 泛型中 自定义约束 的一种方式。

  • ~int:代表int以及int的衍生类型也可以传入

5.2 泛型函数

func Sum[T Number](vals ...T) T {
    var res T
    for _, val := range vals {
        res = res + val
    }
    return res
}
  • [T Number]类型参数列表,表示 T 必须满足 Number 接口。

  • vals ...T变长参数,类型为 T

  • var res T零值初始化,对于数值类型就是 00.0

5.3 使用示例

package main

import "fmt"

func main() {
    fmt.Println(Sum(1, 2, 3))          // 6 (int)
    fmt.Println(Sum(1.1, 2.2, 3.3))    // 6.6 (float64)
    fmt.Println(Sum[int64](10, 20))    // 30 (显式指定类型)
}

六、可比较类型

把「需要用到 == 运算符」的类型参数写成 [T comparable]

package main

import "fmt"

// SliceContains 判断切片里是否包含给定元素
// 约束:T 必须支持 == 比较,因此用 comparable
func SliceContains[T comparable](slice []T, target T) bool {
    for _, v := range slice {
        if v == target { // 这里用了 ==,只有 comparable 才合法
            return true
        }
    }
    return false
}

func main() {
    // 基本类型
    fmt.Println(SliceContains([]int{1, 2, 3}, 2)) // true

    // 字符串
    fmt.Println(SliceContains([]string{"go", "rust"}, "python")) // false

    // 结构体(只要字段全都 comparable 即可)
    type Point struct{ X, Y int }
    ps := []Point{{1, 2}, {3, 4}}
    fmt.Println(SliceContains(ps, Point{3, 4})) // true
}