golang为什么我们没有固定的数据结构[关闭]


129

我正在尝试解决“去编程语言”练习#1.4,这需要我有一套。我可以创建一个set类型,但是为什么语言没有附带呢?来自谷歌(番石榴也是起源于谷歌)的,语言设计者为什么不选择增加对基本数据结构的支持?为什么要强迫您的用户为一套基本的东西创建自己的实现?


11
嗯。想知道为什么投票否决?我来自Java世界,即使没有泛型,我们从一开始就几乎拥有一套。因此,我发现这种行为是一种奇怪的现象
anjanb 2015年

Answers:


83

在某种程度上,因为Go没有泛型(因此您需要为每个类型使用一个set-type,否则将依靠反射,这是相当低效的)。

部分地,因为如果您需要的只是“将单个元素添加/删除到集合中”和“相对节省空间”,则只需使用map[yourtype]bool(就true可以将集合中任何元素的值设置为),或者为了提高空间效率,您可以使用空结构作为值并用于_, present = the_setoid[key]检查是否存在。


1
同样,按照Go的精神,只是用自己的代码写出来,或者“内联”其他代码中的集合,或者在需要时定义自己的集合类型。无论如何,例如在C ++中使用std :: set <T>总是作为函数实现或实现某些其他数据结构的一部分而发生。因此,只需使用映射和切片以及您需要的任何其他构造块直接实现其他数据结构,而无需任何内置集。集合的每次使用都会以稍微不同的方式使用它:)
Bjarke Ebert

1
但是通常您本身并不需要真正的set <Foo>,而是将set <Foo>用作实现更大功能的一部分。我已经看到了无数的代码,在这些代码中,为了包含“可重用”组件而需要做的事情远比仅仅避免这种情况糟得多。所以这里我们有一个set <Foo>,那边的那个函数需要一个set <Bar>,哎呀,我们还有协方差吗,或者如何创建一个WrapperFactory使它看起来像这个东西,等等。也许其他函数实际上只需要一个可以检查成员资格的接口,因此不要向其发送set <Foo>。
Bjarke Ebert 2015年

42
因此,如果它没有泛型,那么如何完全实现“泛型”映射?
Fermin Silva

26
请注意,如果要保存字节,可以使用map[T]struct{}代替map[T]bool
再现


69

一个原因是从地图创建集合很容易:

s := map[int]bool{5: true, 2: true}
_, ok := s[6] // check for existence
s[8] = true // add element 
delete(s, 2) // remove element

联盟

s_union := map[int]bool{}
for k, _ := range s1{
    s_union[k] = true
}
for k, _ := range s2{
    s_union[k] = true
}

路口

s_intersection := map[int]bool{}
for k,_ := range s1 { 
  if s2[k] {
    s_intersection[k] = true
  }
}

实施所有其他设置操作并不难。


10
检查是否存在只是在索引地图。由于如果不在其中,则零值(即false)将正确地表明这一点。无需逗号习惯用法即可进行测试。
icza 2015年

2
交集的实现看起来像区别的实现。
musiphil

1
@Kittsil谢谢你。更新。
萨尔瓦多·达利

34
最好使用map[int]struct{}代替bool,因为空结构在内存中占用0字节。我最近为此gist.github.com/bgadrian/cb8b9344d9c66571ef331a14eb7a2e80
BG Adrian

13
那不是那么容易。这些天来,只需要在需要使用Set的任何地方编写该代码就对我来说很荒谬。收款支持应以任何语言提供。认为更好的答案是Go尚未成熟。我相信将会有足够的图书馆来对此进行介绍。
Stef

5

就像Vatine写道:由于go缺少泛型,因此它必须是语言的一部分,而不是标准库。为此,您将不得不用关键字set,union,intersection,difference,subset来污染语言。

另一个原因是,完全不清楚集合的“正确”实现是什么:

  1. 有一种实用的方法:

    func IsInEvenNumbers(n int) bool {
        if n % 2 == 0 {
            return true
        }
       return false
    }

这是所有偶数的集合。它具有非常高效的查找功能,并且可以通过功能组合轻松地实现并集,相交,差异和子集。

  1. 或者您像Dali所示采取类似has的方法。

映射不存在该问题,因为您存储了与值关联的内容。


2
为了处理自定义集合,Pascal重载了一堆二元(两个精简)运算符:+对于并集,-差,*交集,<=子集,>=超集,=等式,<>不等式和in隶属度。因此,在Go中,它只是一个新关键字- in。另一方面,Pascal的内置设置仅适用于“序数”,即具有基本大小表示形式的整数的任何类型。
kostix 2015年

9
有多种方法来实现集合的事实并没有阻止许多其他语言提供它们。
augurar 2015年

@kostix:Go甚至可以使用语法s[key](好像smap[T]bool)代替key in s
musiphil

2
是否有不简单返回的理由n % 2 == 0
若奥·安德拉德

4

另一种可能性是使用位集,为此至少要有一个软件包,或者您可以使用内置的软件包。在这种情况下,基本上,您需要定义一种将对象转换为索引的方法。


1
我应该注意,我写了上面引用的bitset包的原始版本。
Will Fitzgerald
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.