Go 中的一组结构

Set of structs in Go

如果我有多个要存储的结构:

type Stuff struct {
    a string
    b string
}

我可以用一个 slice 来做,但似乎使用适当的集合结构会使用更少的内存。

不幸的是,Go 没有固定的结构。每个人都建议使用 map[Stuff]struct{} 但这不起作用,因为 Stuff 是一个结构。任何人都有任何好的解决方案?理想情况下无需下载库。

通常 set 和 map 数据结构比在普通数组或切片中存储值列表需要更多的内存,因为 set 和 map 有效地提供了额外的特性,如唯一性或按键检索值。

如果你想要最少的内存使用,只需将它们存储在一个切片中,例如[]Stuff。如果您在多个地方使用这些值,那么只存储它们的指针也可能有利可图,例如[]*Stuff 所以每个存储相同 Stuff 值的地方都可以存储相同的指针(不重复值)。

如果你只想存储唯一的结构值,那么集合确实是最方便的选择,在 Go 中用 map.

实现

map[Stuff]struct{}没有任何问题,有效。地图的requirement for the key type

The comparison operators == and != must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice.

Stuff 是结构,structs in Go are comparable if:

Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.

如果你的 Stuff 结构是你发布的,它是可比较的:它只包含可比较类型的字段 string.

还要注意,如果你想要set数据结构,如果你使用bool作为值类型(例如map[Stuff]bool)和true作为值,则更清楚,然后您可以简单地使用 indexing 来测试值是否在映射中,因为索引表达式会产生值类型的零值(false for bool)如果键(Stuff 在你的例子中)不在地图中,正确地告诉你正在寻找的值不在 "set" 中。 (如果它在地图中,其关联的 true 值是索引表达式的结果 - 正确地告诉它在地图中)。

正如 icza 所说,结构图是一个有效的选项。

但是我不会自己实现 Set,而是使用自 Go 1.18 以来出现的一种新的通用实现。

例如看这个:https://github.com/amit7itz/goset

package main

import (
    "fmt"
    "github.com/amit7itz/goset"
)

type Stuff struct {
    a string
    b string
}

func main() {
    set := goset.NewSet[Stuff]()
    set.Add(Stuff{a: "1", b: "2"})
    set.Add(Stuff{a: "2", b: "3"})
    set.Add(Stuff{a: "2", b: "3"})
    
    fmt.Println(set) // Set[main.Stuff]{{2 3} {1 2}}
    fmt.Println(set.Len()) // 2
}