【发布时间】:2011-05-16 11:11:20
【问题描述】:
在转到std::set 中的等价物是什么?请注意,只有唯一性很重要,我不关心排序。
我考虑过使用虚拟类型,例如 map[string]bool(其中 bool 是虚拟类型),但是我经常发现在 Go 中我需要提供一个不需要的类型,例如用作一个信号量,和这种情况。我错过了一些惯用的 Go 语言吗?
【问题讨论】:
标签: containers go
在转到std::set 中的等价物是什么?请注意,只有唯一性很重要,我不关心排序。
我考虑过使用虚拟类型,例如 map[string]bool(其中 bool 是虚拟类型),但是我经常发现在 Go 中我需要提供一个不需要的类型,例如用作一个信号量,和这种情况。我错过了一些惯用的 Go 语言吗?
【问题讨论】:
标签: containers go
在没有集合的 Perl 等语言中,将具有虚拟值的映射用作集合是常见的做法。我认为这是在 Go 中获取集合的一种可接受的方式,除非您想自己实现它或使用一些第三方实现。当然,您的数据类型必须是允许作为映射中键的类型,即不能是结构、数组或切片。
【讨论】:
使用map[string]bool 完全没问题。
还有一些更花哨的库来处理集合,例如:https://github.com/pwil3058/gosets
但我还是会坚持使用简单的地图,它更惯用、更简单,这总是好的。
【讨论】:
使用map[string]bool(以true 作为虚拟值)或map[string]struct{} 作为一个集合被认为是惯用的围棋。他们每个人都有自己的优点和缺点。
假设:
b := make(map[string]bool)
s := make(map[string]struct{})
使用b 可以更轻松地检查集合是否包含元素:
if b["x"] {
// b has "x"
}
if _, ok := s["x"]; ok {
// s has "x"
}
除非您可以保证b 没有任何false 值,否则使用s 迭代元素会更容易:
for e, v := range b {
if v {
// e is an element of b
}
}
for e := range s {
// e is an element of s
}
s 比 b 更节省内存。
作为替代方案,您可以使用开源库。例如:
github.com/soroushj/menge 实现了所有基本类型的集合。k8s.io/apimachinery/pkg/util/sets 实现整数集(byte、int、int32、int64)和字符串。当然,目前不可能在 Go 中实现泛型集。但是随着 planned 在 Go 中添加泛型,它可以在更高版本(不早于 1.17)中实现。
【讨论】:
如果有人需要一组int,可以使用这个:
package main
import "golang.org/x/tools/container/intsets"
func main() {
var (
a intsets.Sparse
b bool
)
b = a.Insert(9)
println(b) // true
b = a.Insert(9)
println(b) // false
}
【讨论】: