go1.8中引入了泛型,以通用类型的形式表示函数和数据结构。
泛型约束
在非泛型函数中,传递给 interface 形参的实参必须实现 interface 中的所有方法;而泛型函数中,传入的类型实参必须满足类型形参的约束条件,即泛型代码只能使用约束条件允许的操作。
type Stringer interface {
String() string
}
func Stringify[T Stringer](s []T) (ret []string) {
for _, v := range s {
ret = append(ret, v.String())
}
return ret
}
// 使用:
func (s *StrTest) String() string {
return s.Item
}
s := []*StrTest{
{"12"},
{"34"},
}
fmt.Println(Stringify(s))
除此之外,泛型约束中还可添加约束元素;在go中有以下约束方法:
// 没有任何约束
func add[T any](x, y T) T
// 约束 Addable(通过约束接口定义Addable)
func add[T Addable](x, y T) T
// 约束:允许int或float64类型
func add[T int|float64](x, y T) T
// 约束允许底层类型是 string 的类型(包括 string 类型)
func add[T ~string](x, y T) T
类型并集
通过扩展interface实现类型约束:
|
:组合不同类型(即,并集);|
连接的类型不能有交集(接口除外):即不允许int | ~int
;- 并集成员大于1时,不能直接或间接引入comparable接口;
~
:放在类型前面,表示所有底层类型是此类型的类型;- ~后面的类型不能为接口;
- ~后面的类型必须为基本类型;
所有整数的约束:
type Int interface {
int | int8 | int16 | int32 | int64
}
所有底层类型是有序类型(如:type int MyInt
)的约束:
type OrderedType interface {
Integer | Float | ~string
}
type Integer interface {
Signed | Unsigned
}
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}
type Float interface {
~float32 | ~float64
}
类型交集
约束接口中类型可以有多行,若有多行,则取他们的交集:
// 约束为int:因int与~int交集为int
type C interface {
~int
int
}
// 约束为空;因int和float32没有相交的类型
type Bad interface {
int
float32
}
comparable
comparable是go新引入的预定义标识符(一个接口),指代可以使用==或!=来进行比较的类型集合。
any
泛型中引入了any,表示可以接收任意类型;其实any定义即为一个空接口(即interface{}
)
集合SET
go中没提供集合set(存储的元素是唯一的),但可通过map方便实现;为减少空间占用,其值可用空结构(struct{},go会优化为不占用空间)。
type EmptyType struct{}
var empty EmptyType
map中的key是唯一,所以set中的元素即为map中的key;因map中key要是可比较的,所以需要约束为comparable:
// Set 集合类型,不要直接构造,通过NewSet
type Set[T comparable] struct {
m map[T]EmptyType
}
// NewSet 构造Set
func NewSet[T comparable]() *Set[T] {
return &Set[T]{
m: make(map[T]EmptyType),
}
}
// NewSetWith 构造有元素的Set
func NewSetWith[T comparable](items ...T) *Set[T] {
s := &Set[T]{
m: make(map[T]EmptyType, len(items)),
}
for _, v := range items {
s.m[v] = empty
}
return s
}
// Add 添加元素
func (s *Set[T]) Add(val T) {
s.m[val] = empty
}
// Remove 删除元素
func (s *Set[T]) Remove(val T) {
delete(s.m, val)
}
// Contains 检测是否包含元素
func (s *Set[T]) Contains(val T) bool {
_, ok := s.m[val]
return ok
}
// Equals 判断两集合是否相等
func (s *Set[T]) Equals(other *Set[T]) bool {
if other == nil || s.Len() != other.Len() {
return false
}
for k := range s.m {
if _, ok := other.m[k]; !ok {
return false
}
}
return true
}
// Len 获取长度
func (s *Set[T]) Len() int {
return len(s.m)
}
// Clear 清空set
func (s *Set[T]) Clear() {
s.m = make(map[T]EmptyType)
}
// Items 遍历set
func (s *Set[T]) Items() []T {
item := make([]T, 0)
for k := range s.m {
item = append(item, k)
}
return item
}