欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

通用知识-4。小例子

最编程 2024-10-16 09:05:28
...

4.1 map.Keys 获取map的全部key

将map中的所有key取出来,然后存入切片中返回

func Keys[K comparable, V any](m map[K]V) []K {
	res := make([]K, 0, len(m))
	for k, _ := range m {
		res = append(res, k)
	}
	return res
}

类型参数K被用于声明了一个泛型的切片,然后把遍历到的key添加到切片中并返回。
任意的map都能使用Keys泛型函数

func TestKeys(t *testing.T) {
	t.Log(Keys(map[string]struct{}{
		"one":   {},
		"tow":   {},
		"three": {},
	}))
	t.Log(Keys(map[int]int{
		1: 1,
		2: 2,
		3: 3,
	}))
}

在这里插入图片描述

4.2 Set

Set可以存储一组不重复的数据,广泛用于需要去重的场景。很多编程语言比如Java,C++都提供了相应的实现,但是在Go语言中并没有Set类型。
有了泛型可以自己实现了

// 定义 Set
type Set[T comparable] map[T]struct{}

// 创建 Set
func MakeSet[T comparable]() Set[T] {
	return make(Set[T])
}

// 添加元素
func (s Set[T]) Add(k T) {
	s[k] = struct{}{}
}

// 删除元素
func (s Set[T]) Delete(k T) {
	delete(s, k)
}

// 判断是否包含
func (s Set[T]) Contains(k T) bool {
	_, ok := s[k]
	return ok
}

// 返回长度
func (s Set[T]) Len() int {
	return len(s)
}

// 遍历
func (s Set[T]) Iterate(f func(T)) {
	for k := range s {
		f(k)
	}
}

func TestSet(t *testing.T) {
	set := MakeSet[int]()
	set.Add(1)
	set.Add(2)
	set.Add(1)
	set.Add(3)
	t.Log(set.Len()) // 预期 3
	t.Log(set.Contains(2)) // 预期 true
	set.Delete(1) 
	t.Log(set.Len()) // 预期 2
	t.Log(set.Contains(1)) // 预期 false
	sum := 0
	set.Iterate(func(i int) {
		sum += i
	})
	t.Log(sum) // 预期 5
}

在这里插入图片描述

使用泛型实现的Set可适用于任意的可比较类型,行为与其他语言实现的Set基本类似,但是只能函数调用,不能使用下标操作访问元素。
上面实现的Set底层使用一个map实现,并不是线程安全的,还可以进一步使用自定义扩展

type SyncSet[C comparable] struct {
	l sync.RWMutex
	m map[C]struct{}
}

在读操作的时候,加读锁,在写操作的时候加写锁。

4.3 排序 Sort

要对切片中的元素进行排序,在标准库提供sort.Slice之前,每种类型的切片都需要实现sort.Interface接口中的三个方法
在这里插入图片描述

然后使用sort.Sort方法进行排序,即便后来标准库中引入了sort.Slice,但是使用时仍然需要提供一个排序函数。
使用泛型实现一个针对切片的通用排序函数

type Ordered interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
		~float32 | ~float64 |
		~string
}

type orderSlice[O Ordered] []O

func (o orderSlice[O]) Len() int {
	return len(o)
}
func (o orderSlice[O]) Less(i, j int) bool {
	return o[i] < o[j]
}
func (o orderSlice[O]) Swap(i, j int) {
	o[i], o[j] = o[j], o[i]
}
func OrderSlice[O Ordered](s []O) {
	// s 被转换为 []Ordered 类型,也就是 orderSlice,然后排序
	// 因为 orderSlice已经实现了排序的接口,不需要额外实现了
	sort.Sort(orderSlice[O](s))
}
func TestOrder(t *testing.T) {
	is := []int{3, 4, 5, 1, 2}
	OrderSlice(is)
	t.Log(is)
	ss := []string{"he", "ww", "ss"}
	OrderSlice(ss)
	t.Log(ss)
}

在这里插入图片描述

使用泛型实现排序幻术也有一定的局限性,因为不容易处理复杂的符合类型,比如自定义的struct类型。

推荐阅读