[インデックス 14249] ファイルの概要
このコミットは、Go言語の標準ライブラリ reflect
パッケージ内の DeepEqual
関数のドキュメントを改善することを目的としています。特に、マップの比較における挙動(キーは ==
で比較され、値はディープイコールで比較される点)を明確にし、古い表現を修正しています。
コミット
reflect: improve documentation for DeepEqual regarding maps Keys use ==; values use deep equality. Also remove the word 'member'. Fixes #4258.
R=golang-dev, rsc CC=golang-dev https://golang.org/cl/6812055
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8884fabfd739c232c97158b75a6ad0fe72cf9721
元コミット内容
commit 8884fabfd739c232c97158b75a6ad0fe72cf9721
Author: Rob Pike <r@golang.org>
Date: Tue Oct 30 14:42:47 2012 -0700
reflect: improve documentation for DeepEqual regarding maps
Keys use ==; values use deep equality. Also remove the word 'member'.
Fixes #4258.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6812055
---
src/pkg/reflect/deepequal.go | 8 +++++---\n 1 file changed, 5 insertions(+), 3 deletions(-)\n
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index cd364dd9fd..db047963eb 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -122,9 +122,11 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
panic("Not reached")
}
-// DeepEqual tests for deep equality. It uses normal == equality where possible
-// but will scan members of arrays, slices, maps, and fields of structs. It correctly
-// handles recursive types. Functions are equal only if they are both nil.\n+// DeepEqual tests for deep equality. It uses normal == equality where\n+// possible but will scan elements of arrays, slices, maps, and fields of\n+// structs. In maps, keys are compared with == but elements use deep\n+// equality. DeepEqual correctly handles recursive types. Functions are equal\n+// only if they are both nil.\n // An empty slice is not equal to a nil slice.\n func DeepEqual(a1, a2 interface{}) bool {\n if a1 == nil || a2 == nil {\n
変更の背景
このコミットの主な背景は、Go言語の reflect
パッケージにある DeepEqual
関数のドキュメントの曖昧さを解消することです。特に、マップの比較に関する挙動が不明瞭であったため、それを明確にする必要がありました。コミットメッセージにある Fixes #4258
から、この変更がGoのIssue 4258に対応するものであることがわかります。
Issue 4258は、reflect.DeepEqual
がマップを比較する際に、キーが ==
演算子で比較され、値がディープイコールで比較されるという重要な詳細がドキュメントに明記されていないという問題提起でした。また、ドキュメント内で使用されていた「member」という単語が、配列やスライス、構造体のフィールドに対しては適切であるものの、マップの要素を指す場合には「element」の方がより適切であるという指摘もありました。
このコミットは、これらの点を修正し、DeepEqual
の動作をより正確かつ理解しやすくすることを目的としています。
前提知識の解説
Go言語の reflect
パッケージ
reflect
パッケージは、Goプログラムが実行時に自身の構造を検査(リフレクション)することを可能にする機能を提供します。これにより、型情報、フィールド、メソッドなどを動的に操作できます。DeepEqual
関数は、このパッケージの一部であり、2つの値が「深く」等しいかどうかを再帰的に比較するために使用されます。
==
演算子とディープイコール
Go言語における ==
演算子は、プリミティブ型(数値、文字列、ブール値など)や、ポインタ、チャネル、関数、インターフェース、構造体(フィールドがすべて比較可能である場合)、配列(要素がすべて比較可能である場合)の比較に使用されます。しかし、スライス、マップ、関数(nil以外)は ==
演算子では直接比較できません。
==
演算子: 2つの値がメモリ上で同じであるか、または値がビット単位で同じであるかを比較します。構造体や配列の場合、すべてのフィールド/要素が==
で比較可能であれば、それらのフィールド/要素がすべて等しい場合にtrue
を返します。- ディープイコール (Deep Equality):
reflect.DeepEqual
が提供する比較方法です。これは、2つの値が同じ型であり、かつその内容が再帰的に等しいかどうかを判断します。例えば、2つのスライスが同じ要素を同じ順序で持っている場合、それらはディープイコールであると見なされます。マップの場合、キーと値のペアがすべて等しい場合にディープイコールと見なされます。
Go言語におけるマップの挙動
Go言語のマップは、キーと値のペアを格納するハッシュテーブルです。マップのキーは比較可能でなければなりません。これは、キーが ==
演算子で比較できる型である必要があることを意味します。例えば、スライスや関数はマップのキーにはなれません。
マップの比較において、reflect.DeepEqual
は以下のルールに従います。
- 両方のマップが
nil
であるか、両方がnil
でないが長さが同じであるかをチェックします。 - 各マップのキーを反復処理し、一方のマップに存在するキーがもう一方のマップにも存在するかどうかを確認します。キーの比較には
==
演算子が使用されます。 - 対応するキーが見つかった場合、そのキーに関連付けられた値が
DeepEqual
を使用して再帰的に比較されます。
このコミット以前のドキュメントでは、この「キーは ==
、値はディープイコール」という重要なニュアンスが明確に記述されていませんでした。
技術的詳細
このコミットは、src/pkg/reflect/deepequal.go
ファイル内の DeepEqual
関数のコメントブロックを修正しています。
変更前は、DeepEqual
の説明が以下のようになっていました。
// DeepEqual tests for deep equality. It uses normal == equality where possible
// but will scan members of arrays, slices, maps, and fields of structs. It correctly
// handles recursive types. Functions are equal only if they are both nil.
この説明には以下の問題点がありました。
- マップの比較の詳細が不明確: マップのキーと値がどのように比較されるかについて言及がありませんでした。
- 「member」という単語の不適切さ: 配列、スライス、構造体に対して「member」という単語は適切ですが、マップの要素を指す場合には「element」の方がより一般的で正確です。
コミットによって、このコメントは以下のように変更されました。
// DeepEqual tests for deep equality. It uses normal == equality where
// possible but will scan elements of arrays, slices, maps, and fields of
// structs. In maps, keys are compared with == but elements use deep
// equality. DeepEqual correctly handles recursive types. Functions are equal
// only if they are both nil.
この変更により、以下の点が改善されました。
- マップの比較ルールの明確化:
In maps, keys are compared with == but elements use deep equality.
という一文が追加され、マップのキーが==
で比較され、値がディープイコールで比較されるという重要な挙動が明示されました。これにより、開発者はDeepEqual
がマップに対してどのように動作するかを正確に理解できるようになりました。 - 「member」から「elements」への変更:
scan members
がscan elements
に変更され、より一般的な用語が使用されるようになりました。これは、マップの文脈においてもより自然な表現です。
このドキュメントの改善は、DeepEqual
の正確な動作を理解する上で非常に重要であり、特にマップを扱う際の混乱を避けるのに役立ちます。
コアとなるコードの変更箇所
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -122,9 +122,11 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
panic("Not reached")
}
-// DeepEqual tests for deep equality. It uses normal == equality where possible
-// but will scan members of arrays, slices, maps, and fields of structs. It correctly
-// handles recursive types. Functions are equal only if they are both nil.\n+// DeepEqual tests for deep equality. It uses normal == equality where\n+// possible but will scan elements of arrays, slices, maps, and fields of\n+// structs. In maps, keys are compared with == but elements use deep\n+// equality. DeepEqual correctly handles recursive types. Functions are equal\n+// only if they are both nil.\n // An empty slice is not equal to a nil slice.\n func DeepEqual(a1, a2 interface{}) bool {\n if a1 == nil || a2 == nil {\n
コアとなるコードの解説
このコミットは、reflect/deepequal.go
ファイル内の DeepEqual
関数のドキュメンテーションコメントのみを変更しています。実際の関数のロジックには一切変更がありません。
変更されたコメントは、DeepEqual
関数の動作を説明するものです。
-
で始まる行は削除された元のコメントです。+
で始まる行は追加された新しいコメントです。
主な変更点は以下の通りです。
-
scan members
からscan elements
への変更:- 元のコメント:
but will scan members of arrays, slices, maps, and fields of structs.
- 新しいコメント:
but will scan elements of arrays, slices, maps, and fields of structs.
- これは、「member」という単語がマップの文脈では不適切であるという指摘に対応したものです。より一般的な「elements」を使用することで、配列、スライス、マップの要素、および構造体のフィールドを包括的に指すようになりました。
- 元のコメント:
-
マップの比較に関する詳細の追加:
- 新しいコメントに
In maps, keys are compared with == but elements use deep equality.
という文が追加されました。 - この文は、
DeepEqual
がマップを比較する際の具体的な挙動を明確にしています。すなわち、マップのキーはGoの通常の==
演算子で比較され、それに対応する値はDeepEqual
関数自体によって再帰的に(ディープイコールで)比較されるという点です。これは、DeepEqual
の重要な側面であり、以前のドキュメントでは欠落していました。
- 新しいコメントに
この変更は、コードの動作自体には影響を与えませんが、開発者が DeepEqual
を正しく理解し、予期せぬ挙動に遭遇するのを防ぐ上で非常に価値のあるドキュメントの改善です。
関連リンク
- Go Issue 4258: https://github.com/golang/go/issues/4258
- Go CL 6812055: https://golang.org/cl/6812055
参考にした情報源リンク
- Go言語公式ドキュメント
reflect
パッケージ: https://pkg.go.dev/reflect - Go言語におけるマップの比較に関する情報 (一般的なGoのドキュメントやチュートリアル)
- Go言語における
==
演算子と等価性に関する情報 (一般的なGoのドキュメントやチュートリアル)