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
}
如果我有多个要存储的结构:
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
}