TOC

Go set 类型

Go 并没有支持集合类型,我们需要自己实现:

https://go.dev/play/p/uVDCiN4Cbpt

package main

import "fmt"

type Set map[string]bool

func (s Set) Add(item string) {
    s[item] = true
}

func (s Set) Remove(item string) {
    delete(s, item)
}

func (s Set) Contains(item string) bool {
    _, exists := s[item]
    return exists
}

func main() {
    mySet := make(Set)
    mySet.Add("apple")
    mySet.Add("banana")
    mySet.Add("orange")

    for item := range mySet {
        fmt.Println(item)
    }

    fmt.Println(mySet.Contains("apple")) // 输出: true
    fmt.Println(mySet.Contains("grape")) // 输出: false

    mySet.Remove("banana")
    fmt.Println(mySet.Contains("banana")) // 输出: false
}

注意:

  1. 使用 map 做底层存储,因此实现的 set 也是无序的
  2. map 不是线程安全的,如果有并发操作,需要加锁
  3. 如果真的要使用集合类型,应该再扩充一下交集,差集等方法

改进

参考 https://github.com/deckarep/golang-set 的设计:

https://go.dev/play/p/BKWT84lXfuz

package main

import "fmt"

type Set[T comparable] map[T]struct{}

func (s Set[T]) Add(item T) {
    s[item] = struct{}{}
}

func (s Set[T]) Remove(item T) {
    delete(s, item)
}

func (s Set[T]) Contains(item T) bool {
    _, exists := s[item]
    return exists
}

func main() {
    mySet := make(Set[string])
    mySet.Add("apple")
    mySet.Add("banana")
    mySet.Add("orange")

    for item := range mySet {
        fmt.Println(item)
    }

    fmt.Println(mySet.Contains("apple")) // 输出: true
    fmt.Println(mySet.Contains("grape")) // 输出: false

    mySet.Remove("banana")
    fmt.Println(mySet.Contains("banana")) // 输出: false
}

优化点

  1. 空结构体不占空间
  2. 泛型让代码复用性更好