Go语言泛型机制入门

泛型函数

通过 类型参数Go 语言能够编写可以处理多种类型的函数。函数的类型参数位于参数列表前,以中括号括起来:

1
func Index[T comparable](s []T, x T) int

这个申明表示:s 是任意类型 T 的切片,x 是类型 T ,而 T 是一种内建约束 comparable ,代表任意可比较类型。

comparable 是一种很有用的类型约束,满足这种约束的类型 T 可以使用 ==!= 运算符进行比较。下面这个例子,我们通过逐一比较,从切片元素中找出指定值。通过类型参数 TIndex 函数可以支持任意可比较类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import "fmt"

// Index returns the index of x in s, or -1 if not found.
func Index[T comparable](s []T, x T) int {
    for i, v := range s {
        // v and x are type T, which has the comparable
        // constraint, so we can use == here.
        if v == x {
            return i
        }
    }
    return -1
}

func main() {
    // Index works on a slice of ints
    si := []int{10, 20, 15, -10}
    fmt.Println(Index(si, 15))

    // Index also works on a slice of strings
    ss := []string{"foo", "bar", "baz"}
    fmt.Println(Index(ss, "hello"))
}

泛型类型

除了泛型函数,Go 语言还支持 泛型类型 。泛型类型,顾名思义就是带有类型参数的类型定义,设计泛型数据结构时非常有用。

下面是一个简单泛化类型示例,它定义了一个可以保存任意类型的单链表节点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

// List represents a singly-linked list that holds
// values of any type.
type List[T any] struct {
    next *List[T]
    val  T
}

func main() {
}

练习

您可为例子中的链表添加若干函数,来实现单链表功能,以此练练手。

参考答案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package main

import (
    "fmt"
)

// List represents a singly-linked list that holds
// values of any type.
type List[T any] struct {
    next *List[T]
    val  T
}

// create nil list of type T
func NewList[T any] () *List[T] {
    return nil
}

// insert val before list
func (list *List[T]) Insert(val T) (*List[T]) {
    return &List[T]{
        next: list,
        val: val,
    }
}

// insert val after list
func (list *List[T]) Append(val T) (*List[T]) {
    if (list == nil) {
        return list.Insert(val)
    }

    node := &List[T] {
        next: list.next,
        val: val,
    }
    list.next = node
    return list
}

// return new list with elements reversed
func (list *List[T]) Reverse() *List[T] {
    var reversed *List[T]
    for cursor := list; cursor != nil; cursor = cursor.next {
        reversed = reversed.Insert(cursor.val)
    }
    return reversed
}

// traverse list one by one
func (list *List[T]) Traverse(f func (val T, l *List[T])) {
    for cursor := list; cursor != nil; cursor=cursor.next {
        f(cursor.val, cursor)
    }
}

// print list
func (list *List[T]) Print() {
    list.Traverse(func (val T, _ *List[T]) {
        fmt.Printf("%s ", val)
    })
}

// print list with line break
func (list *List[T]) Println() {
    list.Print()
    fmt.Println()
}

func main() {
    // initialize a new list
    l := NewList[string]().Insert("apple").Insert("banana").Append("cat")
    // print it
    l.Println()

    // reverse it
    l = l.Reverse()
    // print it again
    l.Println()
}

总结

Go 语言 1.18 版本开始支持 泛型 编程,可以定义 泛型函数泛型类型 !泛型函数是带有类型参数的函数,能够处理多种数据类型。泛型类型则是带有类型参数的类型,可以用来实现泛化的数据结构。

【小菜学Go语言】系列文章首发于公众号【小菜学编程】,敬请关注:

【小菜学Go语言】系列文章首发于公众号【小菜学编程】,敬请关注: