泛型(Generics)
在 Go 语言(Golang)中,泛型(Generics)是一个相对较新的特性,它允许编写更加通用且类型安全的代码。在没有泛型的情况下,Go 语言的函数和数据结构通常需要针对每种类型单独编写,或者使用 interface{} 处理多种类型,但这种方式会导致类型安全性降低和性能问题。
从 Go 1.18 版本开始,Go 语言引入了泛型,允许开发者编写可以适用于多种类型的函数和数据结构。
基本语法
在 Go 中,泛型主要通过类型参数(Type Parameters)来实现。类型参数是定义在函数、方法或结构体上的,并在调用时指定具体的类型。
示例 1:泛型函数
以下是一个简单的泛型函数示例,它返回两个值中的较大者:
package main
import "fmt"
// 定义一个泛型函数,用于比较两个值
func Max[T comparable](a, b T) T {
if a > b {
return a
}
return b
}
func main() {
fmt.Println(Max(10, 20)) // 输出: 20
fmt.Println(Max("apple", "banana")) // 输出: banana
}
示例 2:泛型数据结构
package main
import "fmt"
// 定义一个泛型堆栈
type Stack[T any] struct {
elements []T
}
// Push 将元素推入堆栈
func (s *Stack[T]) Push(value T) {
s.elements = append(s.elements, value)
}
// Pop 从堆栈中弹出元素
func (s *Stack[T]) Pop() (T, bool) {
if len(s.elements) == 0 {
var zeroValue T
return zeroValue, false
}
index := len(s.elements) - 1
element := s.elements[index]
s.elements = s.elements[:index]
return element, true
}
func main() {
intStack := Stack[int]{}
intStack.Push(10)
intStack.Push(20)
fmt.Println(intStack.Pop()) // 输出: 20, true
fmt.Println(intStack.Pop()) // 输出: 10, true
stringStack := Stack[string]{}
stringStack.Push("hello")
stringStack.Push("world")
fmt.Println(stringStack.Pop()) // 输出: world, true
fmt.Println(stringStack.Pop()) // 输出: hello, true
}
类型约束
Go 的泛型使用类型约束(Type Constraints)来限制类型参数可以接受的类型。常见的类型约束包括:
- any:允许任何类型。
- comparable:表示类型可以使用 == 和 != 进行比较(如数字、字符串、指针等)。
- 自定义接口:你可以定义自己的接口来作为类型约束。
示例 3:使用自定义类型约束
package main
import "fmt"
// 定义一个数值类型的约束接口
type Number interface {
int | int32 | int64 | float32 | float64
}
// Sum 函数计算两个数的和
func Sum[T Number](a, b T) T {
return a + b
}
func main() {
fmt.Println(Sum(10, 20)) // 输出: 30
fmt.Println(Sum(10.5, 20.3)) // 输出: 30.8
}