web-dev-qa-db-ja.com

Golangがconstマップを許可しないのはなぜですか?

次のような定数マップを作成したいと思います。

const (
    running = map[string]string{
        "one": "ONE",
        "two": "TWO",
    }
)

しかし、私はいつでも次のエラーを受け取ります:

const initializer map[string]string literal is not a constant

なぜこれが当てはまるのですか、なぜGolangは他の変数のようにそれらを扱わないのですか?

23
anonrose

https://golang.org/ref/spec#Constants から:

定数値は、ルーン文字、整数、浮動小数点、虚数、または文字列リテラル、定数を表す識別子、定数式、定数である結果を伴う変換、または組み込みの結果値で表されます。任意の値に適用されるunsafe.Sizeof、一部の式に適用されるcapまたはlen、複素数定数に適用されるrealおよびimag、数値定数に適用されるcomplexなどの関数。

tl; dr数値型のみ、文字列およびブール値は定数にすることができ、配列、スライス、マップは数値型ではありません。

19
OneOfOne

私の考えでは、この決定は純粋に実用的でした。Goは非常に地球に近い言語であり(他の「より純粋な」言語とは対照的です)、いくつかの現実世界のマップ実装の興味深い特性の1つは単なる読み取りのためにアクセスすると、内部表現が更新される可能性があります(!)。たとえば、使用状況に関する統計を収集して保存する場合や、値バケットなどを保持する基礎ツリーのバランスを再調整する場合があります。「定数マップ」の存在を許可すると、言語仕様で複雑な制約のセットを明示的に指定することになります—ほとんどの場合、実装に2つのマップ実装が必要です。

別の角度から見てみることもできます。文字列定数を検討してください。そのようなものは、結果のバイナリの_.rodata_セクションに簡単に埋め込むことができ、実際にはメモリ内のそのデータのアドレスで表されます(Goの文字列はより複雑ですが、その詳細は無視しましょう)。つまり、定数文字列は本当に「静的」である可能性があります。それは、メモリ内の単なる一連の静的R/Oバイトです。逆に、マップは複雑な機械を動力とする非常に複雑な獣であり、各マップは実行時にインスタンス化される特別な複雑なオブジェクトですマップを宣言して使用するだけです。最初にmake()する必要があります。チャンネルと同じように、同じ理由で。

繰り返しになりますが、一定のマップをサポートするためにハッキングを行う可能性があります。実装では、マップのキーを前もってソートし、値を使用してR/Oデータの連続領域にシリアル化し、実行時にバイナリ検索を使用して値を検索できます。これは、大きなマップ/特定の主要なパターンにはあまり効果的ではありませんが、おそらく機能します。それでも、それは「通常の」実装とは完全に異なる特殊なマップ実装です。 Goの開発者たちは、トレードオフは利益に値しないと判断したと思います。

2つのフォローアップノート:

  • ご覧のように、読み取り専用マップを比較的簡単にエミュレートできます。キーと値の両方を埋め込むいくつかの構造体タイプのスライスリテラルをキーで事前にソートし、キーでバイナリ検索を実行する関数でラップします。

  • Goの定数は、Cに似た言語のマクロに少し似ていると思います:それらは型付けされておらず、feelがテキストのようです(そうではありませんが、 m結局は気持ちについて話す);-)

    素晴らしい概要については、必ず this を読んでください。

3
kostix