golang,go,博客,开源,编程
golang-set
是一个常用的 Go 语言实现的集合(Set)数据结构库。集合是一个包含多个唯一元素的无序容器。在 Go 中,标准库并没有提供集合类型,因此很多开源库实现了集合的功能,golang-set
就是其中之一。它为 Go 提供了一个简单的实现,使得可以使用集合的功能,比如去重、并集、交集、差集等。
golang-set
简介golang-set
是一个线程安全的集合类型,基于 Go 语言的内建 map
实现。它提供了一个高效且易于使用的集合 API,支持常见的集合操作(如添加、删除、检查元素等)。
该库的 GitHub 仓库地址为:https://github.com/deckarep/golang-set
以下是源码的基本结构和一些关键功能的分析。
Set
type Set struct {
m map[interface{}]struct{}
}
Set
结构体是 golang-set
的核心,包含一个字段 m
,它是一个 map
类型,存储集合的元素。集合的元素被存储为 interface{}
类型,这样就可以存储任何类型的元素。而结构体的值是一个空结构体 struct{}
,这种方式的好处是空结构体不占用内存。
NewSet
// NewSet creates a new set.
func NewSet() Set {
return Set{m: make(map[interface{}]struct{})}
}
NewSet
函数用于创建一个新的空集合。内部使用了 make
函数来创建一个空的 map
,用于存储集合中的元素。
Add
// Add adds an element to the set.
func (s *Set) Add(e interface{}) {
s.m[e] = struct{}{}
}
Add
方法将一个元素添加到集合中。如果该元素已经存在于集合中,由于 map
键的唯一性,添加操作会自动忽略重复的元素。因此,集合保证了元素的唯一性。
Remove
// Remove removes an element from the set.
func (s *Set) Remove(e interface{}) {
delete(s.m, e)
}
Remove
方法从集合中删除指定的元素。它使用 delete
函数从 map
中移除对应的键。
Contains
// Contains checks if the element exists in the set.
func (s *Set) Contains(e interface{}) bool {
_, found := s.m[e]
return found
}
Contains
方法用于检查集合中是否包含指定的元素。它通过访问 map
来判断元素是否存在,如果存在返回 true
,否则返回 false
。
Size
// Size returns the number of elements in the set.
func (s *Set) Size() int {
return len(s.m)
}
Size
方法返回集合中元素的数量,实际上是 map
中键的数量。
Clear
// Clear removes all elements from the set.
func (s *Set) Clear() {
s.m = make(map[interface{}]struct{})
}
Clear
方法会清空集合中的所有元素。它通过重新分配一个新的空 map
来实现这一功能。
Iter
// Iter returns a channel that can be used to iterate over the set.
func (s *Set) Iter() <-chan interface{} {
ch := make(chan interface{})
go func() {
for e := range s.m {
ch <- e
}
close(ch)
}()
return ch
}
Iter
方法返回一个可以用于迭代集合的通道。由于 Go 中的 map
并不是有序的,因此每次迭代时,元素的顺序是不确定的。
// Union returns a new set which is the union of the two sets.
func (s *Set) Union(other Set) Set {
newSet := NewSet()
for e := range s.m {
newSet.Add(e)
}
for e := range other.m {
newSet.Add(e)
}
return newSet
}
Union
方法返回两个集合的并集,它将两个集合中的所有元素合并到一个新的集合中。
// Intersection returns a new set which is the intersection of the two sets.
func (s *Set) Intersection(other Set) Set {
newSet := NewSet()
for e := range s.m {
if other.Contains(e) {
newSet.Add(e)
}
}
return newSet
}
Intersection
方法返回两个集合的交集,只包含两个集合中都有的元素。
// Difference returns a new set which is the difference between the two sets.
func (s *Set) Difference(other Set) Set {
newSet := NewSet()
for e := range s.m {
if !other.Contains(e) {
newSet.Add(e)
}
}
return newSet
}
Difference
方法返回两个集合的差集,即只包含集合 s
中有而集合 other
中没有的元素。
IsEmpty
// IsEmpty checks if the set is empty.
func (s *Set) IsEmpty() bool {
return len(s.m) == 0
}
IsEmpty
方法检查集合是否为空,返回一个布尔值。
Destroy
// Destroy destroys the set and releases resources.
func (s *Set) Destroy() {
s.m = nil
}
Destroy
方法销毁集合,释放其占用的内存资源。
golang-set
的实现并不自动处理并发访问问题。因此,如果在多个 goroutine 中并发访问一个集合,程序需要通过外部同步机制来确保线程安全,例如使用 sync.Mutex
或 sync.RWMutex
来锁定集合。
type ThreadSafeSet struct {
mu sync.RWMutex
set Set
}
func (s *ThreadSafeSet) Add(e interface{}) {
s.mu.Lock()
defer s.mu.Unlock()
s.set.Add(e)
}
func (s *ThreadSafeSet) Remove(e interface{}) {
s.mu.Lock()
defer s.mu.Unlock()
s.set.Remove(e)
}
func (s *ThreadSafeSet) Contains(e interface{}) bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.set.Contains(e)
}
golang-set
的核心设计是基于 Go 内置的 map
数据结构,它通过将元素作为键存储,实现了高效的集合操作,保证了集合中的元素唯一性。库中包含了常见的集合操作,如添加、删除、查找、并集、交集等,且操作简单易用。需要注意的是,golang-set
并不默认提供并发安全保障,如果需要在多线程环境中使用,程序员需要自行处理同步问题。