Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11484] ファイルの概要

コミット

commit 9c3d876db17f34d74b5a4c0b526cb7b956f026ba
Author: Robert Griesemer <gri@golang.org>
Date:   Mon Jan 30 15:31:33 2012 -0800

    go/spec: Update language on map types.
    
    Fixes #2803.
    
    R=r
    CC=golang-dev
    https://golang.org/cl/5601053

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/9c3d876db17f34d74b5a4c0b526cb7b956f026ba

元コミット内容

go/spec: Update language on map types.

このコミットは、Go言語の仕様書におけるマップ型に関する記述を更新するものです。具体的には、マップのキーとして使用できない型に関する説明を修正し、より正確な情報を提供することを目的としています。

変更の背景

Go言語のマップ(map)は、キーと値のペアを格納するための強力なデータ構造です。マップのキーには特定の制約があり、すべての型がキーとして使用できるわけではありません。特に、キーとして使用できる型は「比較可能(comparable)」である必要があります。これは、マップがキーの等価性を判断するために==演算子を使用するためです。

このコミットが行われた2012年1月時点では、Go言語の仕様書において、マップのキーとして使用できない型に関する記述が不正確であった可能性があります。元の記述では「キーの型はstructarray、またはsliceであってはならない」とされていましたが、これは完全ではありませんでした。実際には、structarrayは、その構成要素がすべて比較可能であれば、マップのキーとして使用できます。一方で、function型は比較不可能であり、マップのキーとして使用できません。

このコミットは、Go言語の仕様書(doc/go_spec.html)を更新し、マップのキーとして使用できない型に関する記述をより正確にすることで、開発者の誤解を防ぎ、言語仕様の明確性を向上させることを目的としています。Fixes #2803という記述から、この変更が特定のバグ報告や改善提案に対応するものであることがわかります。

前提知識の解説

Go言語のマップ(map

Go言語のマップは、キーと値のペアを格納するハッシュテーブルの実装です。マップはmake関数で初期化され、map[KeyType]ValueTypeのように宣言されます。

例:

var m map[string]int
m = make(map[string]int)
m["apple"] = 1
fmt.Println(m["apple"]) // 1

比較可能性(Comparability)

Go言語において、ある型が「比較可能」であるとは、その型の値に対して==(等しい)および!=(等しくない)演算子が定義されていることを意味します。マップのキーは、その性質上、一意性を保証し、効率的な検索を行うために比較可能である必要があります。

比較可能な型(マップのキーとして使用可能):

  • ブール型 (bool): trueまたはfalse
  • 数値型 (int, float64, complex128など): 整数、浮動小数点数、複素数。
  • 文字列型 (string): 文字列。
  • ポインタ型 (*T): ポインタは参照するメモリアドレスが等しいかどうかで比較されます。
  • チャネル型 (chan T): チャネルは参照するチャネルオブジェクトが等しいかどうかで比較されます。
  • インターフェース型 (interface{}): インターフェース型は、その動的な型と値が両方とも比較可能であれば、比較可能です。
  • 構造体型 (struct): 構造体のすべてのフィールドが比較可能であれば、その構造体型も比較可能です。
  • 配列型 ([N]T): 配列の要素の型が比較可能であれば、その配列型も比較可能です。

比較不可能な型(マップのキーとして使用不可):

  • スライス型 ([]T): スライスは動的なサイズを持ち、その等価性を判断するには要素の深い比較が必要となるため、比較不可能です。
  • マップ型 (map[K]V): マップ自体も動的なサイズを持ち、その等価性を判断するには要素の深い比較が必要となるため、比較不可能です。
  • 関数型 (func(...)): 関数は比較不可能です。

Goコンパイラは、比較不可能な型をマップのキーとして使用しようとすると、コンパイルエラーを発生させます。

技術的詳細

このコミットは、Go言語の公式仕様書であるdoc/go_spec.htmlの記述を修正しています。具体的には、マップのキー型に関する制約をより正確に記述するために、以下の変更が行われました。

元の記述: The comparison operators == and != (§<a href="#Comparison_operators">Comparison operators</a>) must be fully defined for operands of the key type; thus the key type must not be a struct, array or slice. (キー型のオペランドに対して比較演算子==!=が完全に定義されている必要があります。したがって、キー型はstructarray、またはsliceであってはなりません。)

変更後の記述: The comparison operators == and != (§<a href="#Comparison_operators">Comparison operators</a>) must be fully defined for operands of the key type; thus the key type must not be a function, map, or slice. (キー型のオペランドに対して比較演算子==!=が完全に定義されている必要があります。したがって、キー型はfunctionmap、またはsliceであってはなりません。)

この変更のポイントは以下の通りです。

  1. structarrayの削除: 比較可能なstructarrayはマップのキーとして使用できるため、これらを「キーであってはならない」というリストから削除しました。これは、structarrayが、その内部のすべての要素が比較可能であれば、比較可能であるというGo言語のセマンティクスに合致します。
  2. functionの追加: function型はGo言語において比較不可能な型であるため、マップのキーとして使用できないことを明示するためにリストに追加されました。
  3. mapの維持: map型自体も比較不可能な型であるため、引き続きリストに残されています。
  4. sliceの維持: slice型も比較不可能な型であるため、引き続きリストに残されています。

この修正により、Go言語の仕様書はマップのキー型に関するルールをより正確に反映し、開発者がマップを適切に使用するための明確なガイドラインを提供できるようになりました。

コアとなるコードの変更箇所

--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-\t"Subtitle": "Version of January 21, 2012"\n+\t"Subtitle": "Version of January 30, 2012"\n }-->
 
 <!--
@@ -1150,7 +1150,8 @@ KeyType     = Type .\n <p>\n The comparison operators <code>==</code> and <code>!=</code>\n (§<a href="#Comparison_operators">Comparison operators</a>) must be fully defined\n-for operands of the key type; thus the key type must not be a struct, array or slice.\n+for operands of the key type; thus the key type must not be a function, map, or\n+slice.\n If the key type is an interface type, these\n comparison operators must be defined for the dynamic key values;\n failure will cause a <a href=\"#Run_time_panics\">run-time panic</a>.\n```

## コアとなるコードの解説

このコミットは、`doc/go_spec.html`ファイル内の2つの箇所を変更しています。

1.  **仕様書のバージョン日付の更新**:
    ```diff
    -\t"Subtitle": "Version of January 21, 2012"\n+\t"Subtitle": "Version of January 30, 2012"\n    ```
    これは、仕様書が更新された日付を反映するための単純な変更です。

2.  **マップキー型の制約に関する記述の修正**:
    ```diff
    -for operands of the key type; thus the key type must not be a struct, array or slice.\n+for operands of the key type; thus the key type must not be a function, map, or\n+slice.\n    ```
    この行がこのコミットの主要な変更点です。
    *   削除された部分 (`struct, array or slice`): 以前の記述では、`struct`と`array`がマップのキーとして使用できないとされていましたが、これは誤りでした。Go言語では、`struct`や`array`のすべてのフィールド(または要素)が比較可能であれば、それら自体も比較可能となり、マップのキーとして使用できます。
    *   追加された部分 (`function, map, or slice`): 新しい記述では、`function`型がマップのキーとして使用できないことが明示的に追加されました。`map`型と`slice`型は以前から比較不可能であり、引き続きマップのキーとして使用できないため、リストに残されています。

この変更により、Go言語の仕様書は、マップのキーとして使用できる型とできない型に関する正確な情報を提供するようになりました。これは、Go言語の設計思想である「シンプルさと明確さ」を追求する上で重要な改善です。

## 関連リンク

*   Go言語の公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
*   Go言語の仕様書: [https://go.dev/ref/spec](https://go.dev/ref/spec)

## 参考にした情報源リンク

*   Go言語のマップキーの比較可能性に関する情報:
    *   [https://go.dev/blog/maps](https://go.dev/blog/maps) (Go言語のマップに関する公式ブログ記事)
    *   [https://golangbyexample.com/go-map-key-types/](https://golangbyexample.com/go-map-key-types/) (Go言語のマップキー型に関する解説)
    *   [https://bitfieldconsulting.com/golang/map-keys](https://bitfieldconsulting.com/golang/map-keys) (Go言語のマップキーに関する解説)
*   GitHubのコミットページ: [https://github.com/golang/go/commit/9c3d876db17f34d74b5a4c0b526cb7b956f026ba](https://github.com/golang/go/commit/9c3d876db17f34d74b5a4c0b526cb7b956f026ba)
*   Go Vulnerability Database (GO-2024-2803): [https://pkg.go.dev/vuln/GO-2024-2803](https://pkg.go.dev/vuln/GO-2024-2803) (ただし、このコミットが修正した`#2803`は、この脆弱性とは直接関係ない可能性が高いです。コミットの文脈から、より古い、仕様に関する内部トラッキングIDであると推測されます。)