申明参数为泛型类型

在线运行open in new window启动 AI 助手open in new window

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

func add2(a, b string) string {
	return a + b
}

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

func main() {
	fmt.Println(add1(1, 2))         // 3
	fmt.Println(add2("one", "two")) // onetwo

	fmt.Println(add(1, 2))         // 3
	fmt.Println(add("one", "two")) // onetwo
}

代码演示了 Go 语言中的泛型函数(generic functions)特性。在此之前,Go 语言并没有原生支持泛型,因此需要使用不同类型参数的函数进行重复的编写。而在 Go 1.18 中,引入了对泛型的支持,可以使用类型参数来编写通用函数。

在代码中,add1 和 add2 函数分别接受两个整型和两个字符串类型的参数,并返回它们的和。而 add 函数使用了类型参数 T,表示接受任意一种类型的参数,并返回它们的和。在函数体内,使用了 + 运算符,这是因为我们已经声明了类型参数 T 可以是 int 或 string 类型,而这两个类型都支持 + 运算符。

在 main 函数中,我们测试了这三个函数的功能,并传入了不同类型的参数来进行测试,可以看到泛型函数 add 可以成功地接受不同类型的参数并进行求和运算。

使用 go 内置的泛型定义

在线运行open in new window启动 AI 助手open in new window

func find[T comparable](list []T, target T) int {
	for idx, it := range list {
		if it == target {
			return idx
		}
	}

	return -1
}

func main() {
	fmt.Println(find[int]([]int{1, 2, 3}, 2))
	fmt.Println(find[int]([]int{1, 2, 3}, 0))

	fmt.Println(find[string]([]string{"one", "two", "three"}, "two"))
	fmt.Println(find[string]([]string{"one", "two", "three"}, "four"))
}

程序使用泛型的函数 find,用于在任何实现了 comparable 接口的切片中查找目标元素的索引。函数定义中的 [T comparable] 表示 T 类型必须实现 comparable 接口,即可进行相等比较。

函数使用 for 循环遍历切片,如果找到了目标元素,则返回其索引,否则返回 -1。

在 main 函数中,首先使用 find[int] 查找整型切片 [1, 2, 3] 中的元素 2,应该返回 1;接着使用 find[int] 查找整型切片 [1, 2, 3] 中的元素 0,应该返回 -1。最后使用 find[string] 查找字符串切片 ["one", "two", "three"] 中的元素 "two",应该返回 1;接着使用 find[string] 查找字符串切片 ["one", "two", "three"] 中的元素 "four",应该返回 -1。

使用 constraints 定义的类型

在线运行open in new window启动 AI 助手open in new window

// type Integer interface {
// 	Signed | Unsigned
// }

// type Float interface {
// 	~float32 | ~float64
// }

// type Ordered interface {
// 	Integer | Float | ~string
// }

func greatThan[T constraints.Ordered](a, b T) bool {
	return a > b
}

func main() {
	fmt.Println(greatThan(1, 2))         // false
	fmt.Println(greatThan("one", "two")) // false
}

代码使用了类型约束(constraints),其中定义了一个函数 greatThan,它接受两个参数 a 和 b,这两个参数的类型必须是 constraints.Ordered 约束类型,也就是说它们必须实现了接口 Ordered。

Ordered 接口中规定了一些比较操作,比如 Less、Equal、Greater 等,这些操作符在实现时,需要遵循特定的语法和规则。在这个函数中,我们调用了参数 a 和 b 的比较操作符,判断了它们的大小关系,最终返回了一个布尔值。

在 main 函数中,我们调用了 greatThan 函数,传入了两个参数,一个是 int 类型的 1,一个是 int 类型的 2,它们都实现了 Ordered 接口,所以可以被传入到 greatThan 函数中。同样的,我们也传入了两个 string 类型的参数,在这个例子中,它们的比较操作符也是有效的。

自定义约束的类型

在线运行open in new window启动 AI 助手open in new window

type Number interface {
	~int | float32 // ~X 表示支持 X 的衍生类型
}

type Salary int

func sum[T Number](list []T) T {
	var t T

	for _, it := range list {
		t += it
	}

	return t
}

func main() {
	fmt.Println(sum[int]([]int{1, 2, 3}))
	fmt.Println(sum[float32]([]float32{1.1, 2.2, 3.3}))
	fmt.Println(sum[Salary]([]Salary{100, 200, 300}))
}

代码定义了一个 Number 接口,包含 int 和 float32 类型。同时,还定义了一个 Salary 类型,表示工资。然后,定义了一个 sum 泛型函数,它接收一个 Number 类型的 slice,并返回这些数的和。在 main 函数中,我们分别传递了 int、float32 和 Salary 类型的 slice 给 sum 函数,并输出了它们的和。由于 int 和 float32 实现了 Number 接口,所以可以直接传递;而 Salary 类型没有实现 Number 接口,所以会报错。

Last Updated:
Contributors: Bob Wang