go 泛型

go 泛型

1. 类型参数(Type parameters)

Go语言的泛型(Generic)叫做类型参数。泛型可以让我们代码适应不同类型的参数。

泛型函数

声明语法

// 声明一个带有泛型的函数
// T 指类型参数,就是一个参数,代表类型
// Constraint 是对类型参数T的约束,限制T的取值, 可以是int、string、any等类型,any可以是任意类型的意思
// s 是要打印的参数
func name[T {Constraint}](s T) {}

函数名和函数参数列表之间插入了一组方括号,来表示类型参数。跟函数参数一样,我们需要为每一个类型参数指定「类型」,这种类型的类型Go语言称之为约束。

示例

// 打印函数
func print[T any](s ...T) {
    for _, i := range s {
        fmt.Println(i)
    }
}

T表是切片成员的类型,但T的实际类型在定义print()的时候是不确定的,需要在调用该函数的时候指明。也就是说,我们在调用print()函数的时候需要额外传入一个特殊参数来指定T的具体类型。这种特殊的参数就叫类型参数。

使用泛型函数

func main() {
    // 约束为int类型
    print[int](1, 3, 4) 
    
    // 约束为string类型
    print[string]("derek", "阿瓦达啃大瓜", "奇摩鸡")
    
    // 任意类型
    print[any](1, "wo")
    
    // 任意类型,与any一样
    print[interface{}](1, "wo")
    
    // 不指定约束类型,则输入的数据类型必须为同一种类型
    print(1, 3, 4)
}

指定出参类型

// 指定返回参数的类型是T
func add[T any](a, b T) T {
    return a + b
}

// 也可以返回指针
func addV2[T any](a T) *T {
    return &a 
}

func main() {
    // 约束为int类型
    add[int](1, 3, 4) 
    
    // 约束为string类型
    add[string]("derek", "阿瓦达啃大瓜")  
}

// 结果输出:
// 8
// derek阿瓦达啃大瓜

泛型类型

// 定义一个泛型的数组
type Nums[T any] []T

// 定义一个泛型的map, map的K比较特殊,必须使用comparable来约束, 否则不生效
type Map[K comparable, V any] map[K]V

2. 内置约束 comparable

泛型参数一般都可以进行运算操作,但有两个符号是特殊的,就是:== 和 !=。 如果参数需要使用这两个作比较,则一定要使用comparable。

// 比较两个参数t、v是否相等
func Comp[T comparable](s []T, v T) int {
    for i, t := range s {
        if t == v {
            return i
        }
    }
    return 0
}

如果把上述的comparable改为any,则会报错:

invalid operation: t == v (type parameter T is not comparable with ==)

map数据的key有需要使用comparable,否则也会报错

3.自定义约束 (Constraint)

泛型的Constraint,可以使用any、int、string、comparable都可以,还可以定义一个interface来定义约束

// Addable 泛型操作
type Addable interface {
    // 约束类型
    ~int | float32 | ~float64 | string
}

func add[T Addable](a, b T) T {
    return a + b
}

上述的"~"符号不是必须的,但加上"~"的话,系统会兼容基类参数类型。例如,这里定义了一个类型Int

type Int int

int就是Int的基类类型,如果是这时候Addable的是~int,则Int会在其约束范围内,否则不在约束范围内。

并集约束

取约束类型的并集,intfloat32都是约束

type Addable interface {
    int | float32 
}

交集约束

type Stringer interface {
    String() string
}

type Addable interface {
    int
    Stringer
}

这种情况下,Addable约束的类型,必须是int类型,且这个类型实现 Stringer 接口。

你可能感兴趣的:(go 泛型)