golangなぜデータ構造が設定されていないのか[終了]


129

私はセットを持っていることを必要とする「囲碁プログラミング言語」演習#1.4を解決しようとしています。セットタイプを作成できますが、言語にセットタイプが付属していないのはなぜですか?行く、グアバも生まれたグーグルから来たのに、なぜ言語デザイナーは基本的なデータ構造のサポートを追加することを選ばなかったのですか?なぜユーザーにセットとして非常に基本的な独自の実装を作成させるのですか?


11
うーん。なぜ反対票を投じるのだろう?私は、ジェネリックがなくても、最初からほぼ正しいセットを持っていたJavaの世界から来ています。だから、私はこの振る舞いは奇妙なものだ
anjanb

回答:


83

Goにはジェネリックがないためです(そのため、すべてのタイプに1つのセットタイプが必要か、リフレクションに頼るので、かなり非効率的です)。

必要なのは、「セットへの個々の要素の追加/削除」と「比較的スペース効率の良い」ことだけなので、aを使用するだけでかなりの量を得ることができます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
2017年


69

1つの理由は、マップからセットを簡単に作成できることです。

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)が適切にそれを伝えます。テストにコンマOKイディオムは必要ありません。
icza

2
交差の実装は、違いの実装に似ています。
musiphil

1
@Kittsilありがとうございます。更新しました。
サルバドールダリ

34
空の構造体はメモリ内で0バイトを占有するため、のmap[int]struct{}代わりに使用する方が最適boolです。私は最近、このgist.github.com/bgadrian/cb8b9344d9c66571ef331a14eb7a2e80の
BG Adrian

13
それはそれほど簡単ではありません。Setを使用する必要のあるすべての場所でそのコードを記述する必要があるだけで、最近はばかげているようです。コレクションのサポートは、任意の言語で提供する必要があります。より良い答えは、囲碁はまだ成熟していないということです。それを十分にカバーするライブラリーがあると私は確信しています。
Stef

5

Vatineが書いたように:goにはジェネリックが不足しているため、標準ライブラリではなく言語の一部である必要があります。そのためには、キーワードセット、ユニオン、インターセクション、差異、サブセットで言語を汚染する必要があります...

もう1つの理由は、セットの「正しい」実装が何であるかがまったく明確でないことです。

  1. 機能的なアプローチがあります:

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

これはすべてのintのセットです。これは非常に効率的なルックアップとユニオンを備えており、機能的な構成によって簡単に行うことができます。

  1. または、ダリが示したようなhas-likeアプローチを実行します。

値に関連付けられたものを格納するため、マップにはその問題はありません。


2
パスインは、組込みセットを処理するために、一連のバイナリ(2引数)演算子をオーバーロードします:+ユニオン、-差分、*交差、<=サブセット、>=スーパーセット、=等式、<>不等式、およびinメンバーシップ。したがって、Goでは、新しいキーワードは1つだけになります- in。一方、Pascalの組み込みセットは、「序数」、つまり、あるサイズの整数値の基になる表現を持つすべての型でのみ機能します。
kostix 2015

9
セットを実装する方法が複数あるという事実は、他の多くの言語がそれらを提供することを妨げていません。
オーギュラー

@kostix:ゴーも、構文を使用することができますs[key](あるかのようsだったmap[T]bool)の代わりにkey in s
musiphil

2
単に戻るのではない理由はn % 2 == 0何ですか?
ジョアン・アンドラーデ

4

もう1つの可能性は、ビットセットを使用することです。これには、少なくとも1つのパッケージが存在するか、組み込みの大きなパッケージを使用できます。この場合、基本的には、オブジェクトをインデックスに変換する方法を定義する必要があります。


1
上記のビットセットパッケージのオリジナルバージョンを作成したことに注意してください。
フィッツジェラルド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.