泛型类型与方法
本教程共 80 篇 · 第 49 篇 · 更新于 2026-07-27 · 约 8 分钟阅读
49. 泛型类型与方法
本节目标:学会定义泛型结构体、泛型切片等类型,给泛型类型加方法,了解 1.24 泛型类型别名和 1.26 自引用约束。
泛型结构体
不只是函数,类型也可以有类型参数。最常见的是泛型结构体:
package main
import "fmt"
// 泛型栈
type Stack[T any] struct {
items []T
}
func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}
func (s *Stack[T]) Pop() (T, bool) {
if len(s.items) == 0 {
var zero T // 泛型零值
return zero, false
}
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
return item, true
}
func main() {
// 整数栈
intStack := &Stack[int]{}
intStack.Push(1)
intStack.Push(2)
v, _ := intStack.Pop()
fmt.Println(v) // 2
// 字符串栈
strStack := &Stack[string]{}
strStack.Push("hello")
s, _ := strStack.Pop()
fmt.Println(s) // hello
}
注意几个要点:
- 类型声明
type Stack[T any] struct{...}带类型参数 - 方法的接收者要带上类型参数:
func (s *Stack[T]) Push(item T) - 泛型零值用
var zero T声明,T 的零值取决于具体类型
Note创建泛型类型实例时通常需要指定类型实参:
Stack[int]{}。但如果编译器能推断出来,也可以省略。
泛型切片
给切片类型加上泛型参数:
type List[T any] []T
func main() {
nums := List[int]{1, 2, 3}
nums = append(nums, 4)
fmt.Println(nums) // [1 2 3 4]
strs := List[string]{"a", "b"}
fmt.Println(strs) // [a b]
}
泛型切片继承了底层切片的所有操作(append、len、cap、range 等),还能加自己的方法:
func (l List[T]) Filter(f func(T) bool) List[T] {
var result List[T]
for _, v := range l {
if f(v) {
result = append(result, v)
}
}
return result
}
func main() {
nums := List[int]{1, 2, 3, 4, 5}
evens := nums.Filter(func(n int) bool { return n%2 == 0 })
fmt.Println(evens) // [2 4]
}
泛型 map
type Map[K comparable, V any] map[K]V
func main() {
m := Map[string, int]{
"apple": 5,
"banana": 3,
}
fmt.Println(m["apple"]) // 5
}
K 必须是 comparable,因为 map 的 key 必须可比较。
泛型方法
Go 的方法不能有自己的类型参数。也就是说,方法的类型参数只能来自接收者:
type Box[T any] struct {
Value T
}
// OK:用了接收者的类型参数 T
func (b *Box[T]) Get() T {
return b.Value
}
// 编译错误:方法不能有自己的类型参数
// func (b *Box[T]) Convert[U any]() U {
// ...
// }
WarningGo 不支持给方法加额外的类型参数。如果你需要这种功能,改成泛型函数:
// 不行:方法带额外类型参数
// func (b *Box[T]) Convert[U any]() U
// 行:用泛型函数替代
func Convert[T any, U any](b *Box[T], f func(T) U) U {
return f(b.Value)
}
泛型接口
接口也可以有类型参数:
type Container[T any] interface {
Add(item T)
Get(index int) (T, bool)
Size() int
}
// 实现
type ArrayList[T any] struct {
items []T
}
func (a *ArrayList[T]) Add(item T) {
a.items = append(a.items, item)
}
func (a *ArrayList[T]) Get(index int) (T, bool) {
if index < 0 || index >= len(a.items) {
var zero T
return zero, false
}
return a.items[index], true
}
func (a *ArrayList[T]) Size() int {
return len(a.items)
}
func main() {
var c Container[int] = &ArrayList[int]{}
c.Add(42)
v, ok := c.Get(0)
fmt.Println(v, ok) // 42 true
}
Go 1.24:泛型类型别名
Go 1.24 开始支持泛型类型别名。你可以给泛型类型起别名,别名也带类型参数:
package main
import "fmt"
// 泛型类型
type OrderedMap[K comparable, V any] struct {
data map[K]V
}
// Go 1.24:泛型类型别名
type StringMap[V any] = OrderedMap[string, V]
func main() {
// 用别名,只写一个类型参数
m := StringMap[int]{
data: map[string]int{"a": 1},
}
fmt.Println(m.data["a"]) // 1
}
StringMap[V] 是 OrderedMap[string, V] 的别名,固定了 K 为 string,V 还是泛型。使用时只需指定一个类型参数。
Note泛型类型别名是 Go 1.24(2025 年 2 月)引入的。之前的版本不支持给泛型类型起别名。
Go 1.26:自引用约束
Go 1.26 允许泛型类型在自己的类型参数列表中引用自身。这在定义递归类型约束时非常有用:
package main
import "fmt"
// Go 1.26:自引用约束
type Adder[A Adder[A]] interface {
Add(A) A
}
// 实现
type IntAdder int
func (a IntAdder) Add(b IntAdder) IntAdder {
return a + b
}
func algo[A Adder[A]](x, y A) A {
return x.Add(y)
}
func main() {
result := algo(IntAdder(3), IntAdder(5))
fmt.Println(result) // 8
}
Adder[A Adder[A]] 表示 A 必须是一个实现了 Add(A) A 的类型,而且 A 就是它自己。这种自引用约束在定义代数数据结构(如 F-代数)时特别有用。
Tip自引用约束是 Go 1.26(2026 年 2 月)的新特性。之前版本写
Adder[A Adder[A]]会编译错误。这是高级特性,日常开发用得不多,但在某些抽象数据结构设计中很有价值。
小结
泛型类型的要点:
- 泛型结构体/切片/map:
type Name[T any] ... - 方法的类型参数只能来自接收者,方法不能有额外类型参数
- 泛型零值用
var zero T声明 - Go 1.24 支持泛型类型别名
- Go 1.26 支持自引用约束
下一章讲类型推断规则和泛型使用的最佳实践。