引言#

很久之前就听到过泛型的声音了,但是对于泛型我一直处于没碰到也懒得碰的状态,但是今天偶然看了一下 roadMap ,因此我打算开始碰一下我的泛型了,也就是基础学习一下,感觉没有需求不大会写的样子

泛型#

现在有个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func head(slice []int) (*int, bool) {
if len(slice) > 0 {
return &slice[0], true
}
return nil, false
}

func main(){
slice := int[]{1,2,3,4,5}
a , ok := head(slice)
if ok {
fmt.println(a)
}
}

以上代码可以看出特别简单

那么如果我们还要再实现一个 func head(slice []string) (*string, bool) { 呢?

这个时候就需要应用泛型了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func head[T any](slice []T) (*T, bool) {
if len(slice) > 0 {
return &slice[0], true
}
return nil, false
}

func main() {
slice := []int{1, 2, 3}
a, ok := head(slice)
if ok {
fmt.Println(*a)
}

slice2 := []string{"a", "b", "c"}
b, ok := head(slice2)
if ok {
fmt.Println(*b)
}
}

这个时候就可以既使用 int 又 使用string了,我们直接将他定义成了 head[T any]

那么我们还可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// version 1 
func head[T int|string](slice []T)(*T, bool){
if len(slice) > 0 {
return &slice[0] , true
}
return nil , false
}

// version 2
type Header interface {
int | string | ~int32
}

func head[T Header](slice []T)(*T, bool){
if len(slice) > 0 {
return &slice[0] , true
}
return nil ,false
}
  • [ T int | string ] 表示 T 可以表示为 int , 或者 string

  • type Header interface { int | string | ~int32 } 表示 Header 可以表示 int, string 以及底层用 int32 实现的类型 , 这种接口只能用于 泛型约束,不能写作: var h Header

    注意这里的 ~ 这个表示底层用 Int32 实现的类型都可以用 T 接收使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // such as :
    type Header interface {
    int | string | ~int32
    }

    func head[T Header](slice []T)(*T, bool){
    if len(slice) > 0 {
    return &slice[0] , true
    }
    return nil ,false
    }

    type MyInt int
    type MyInt32 int32

    func main() {
    slice1 := []int{ 1, 2, 3}
    slice2 := []int32{1,2,3}

    head(slice1) // 这个是不通过的
    head(slice2) // 这个是通过的
    }

当我们想要获取这个函数的时候(不使用):

1
2
3
f := head[string]

f([]string{"1","2"})

Header中也可以嵌入其他的接口和方法:

1
2
3
4
5
6
// 这样子表示 参数 必须符合这些类型,并且还需要实现这个接口
type Header interface{
int | string | ~int32

error
}

但是不能嵌入带有方法的接口:

1
2
3
4
5
6
7
8
9
// 下面是错误的示范:
type Int interface {
int | string
error
}

type Header interface{
~int | string | Int
}

我们还可以实现泛型结构体

1
2
3
4
type Box[T any ,S string] struct{
Value T
Str S
}

泛型是结构体和函数的一部分,所以当我们需要给变量赋值的时候就需要写成

var b Box[string]f := head[string]

同时我们需要知道 var b Box[int]var b Box[string] 是两种不同的类型,需要区分

同时也有泛型方法

1
2
3
func (b Box[t]) Map() {
return
}

接口泛型类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type Getter[T any] interface{
Get() T
}

type Box[T any] struct {
Value T
}

func (box Box[T]) Get() T {
return box.Value
}

func main(){
box := Box[int]{10}
a := box.Get()
fmt.println(a)
}

总结#

其实个人觉得这个 泛型 非常鸡肋,至少我没看过多少人会使用这个泛型,哪怕使用也就是使用基本作用

类型推断#

Go语言的类型推断是指在声明变量时,编译器能够根据变量的初始化值自动推断出变量的类型,而无需显式地指定类型。这种特性使得Go语言的代码更加简洁和易读。

  1. 在变量初始化时进行类型推断

    1
    2
    x = 10              // 编译器会自动推断出x的类型为int
    y = "Hello world!" // 编译器会自动推断出y的类型为string
  2. 对函数返回值类型进行推断

    1
    2
    3
    4
    // 计算两个整数的和并返回  
    func add(a, b int) int {
    return a + b
    }
  3. 复合类型的类型推断(struct)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    type Person struct {  
    Name string
    Age int
    }

    p := Person{Name: "lipeilun", Age: 30} // 使用类型推断来创建Person对象
    numbers := []int{1, 2, 3, 4, 5} // 使用类型推断来创建整数切片
    // 使用类型推断来创建map对象
    scores := map[string]int{
    "lipeilun": 90,
    "xiaobin": 85,
    "windeal": 88,
    }