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

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

このコミットは、Go言語の標準ライブラリ sort パッケージ内の example_multi_test.go ファイルに対する修正です。具体的には、Example_sortMultiKeys というテスト関数内のコメントとソートの呼び出し方法が変更されています。

コミット

commit fb25a61872f3679cd2c4880e93cc2a44a9d373f7
Author: Andriy Lytvynov <lytvynov.a.v@gmail.com>
Date:   Fri Sep 6 16:49:34 2013 -0400

    sort: fix Example_sortMultiKeys
    
    Old example referenced global var from multiSorter.Sort and ignored it's argument.
    Changed one of example calls to actually pass slice to sort.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/13551044

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

https://github.com/golang/go/commit/fb25a61872f3679cd2c4880e93cc2a44a9d373f7

元コミット内容

このコミットは、sort パッケージの example_multi_test.go 内の Example_sortMultiKeys 関数の修正です。

元の問題点は以下の通りです。

  1. multiSorter.Sort メソッドが、その引数として渡されたスライスを無視し、multiSorter 構造体内のグローバル変数(ms.changes)を参照していた。
  2. これにより、OrderedBy(user, increasingLines) のように sort.Sort を直接呼び出す例が、意図した通りに動作していなかった。この呼び出しでは、multiSorterchanges フィールドが初期化されず、ソート対象のスライスが正しく設定されていなかった。

変更の背景

このコミットの背景には、Go言語の標準ライブラリのドキュメントとテストの正確性を向上させるという目的があります。sort パッケージは、Go言語でスライスをソートするための基本的な機能を提供します。特に、複数のキーに基づいてソートを行う multiSorter のような高度な例は、ユーザーがこのパッケージを効果的に利用するための重要なリファレンスとなります。

しかし、既存の Example_sortMultiKeys は、multiSorter.Sort メソッドの実装と、その呼び出し方法において誤解を招く可能性のある記述と動作をしていました。具体的には、multiSorter.Sort メソッドが引数として受け取る changes スライスを内部で利用せず、multiSorter 構造体自身の changes フィールドに依存していました。これは、multiSorter のインスタンスが作成される際に changes フィールドが初期化されないため、ソートが正しく行われない原因となっていました。

この修正は、multiSorter の設計意図と sort.Sort インターフェースの正しい利用方法を反映させることで、ドキュメントの正確性を高め、ユーザーが sort パッケージをより適切に理解し、利用できるようにすることを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念と sort パッケージの知識が必要です。

  • Go言語のスライス (Slice): スライスはGo言語の可変長シーケンス型です。配列の上に構築され、動的なサイズ変更が可能です。ソートの対象となるデータは通常スライスとして表現されます。
  • Go言語のインターフェース (Interface): Go言語のインターフェースは、メソッドのシグネチャの集合を定義します。型がそのインターフェースのすべてのメソッドを実装していれば、その型はそのインターフェースを満たします。sort パッケージでは、sort.Interface インターフェースが定義されており、ソート可能な型はこのインターフェースを実装する必要があります。
    • Len() int: スライスの要素数を返します。
    • Less(i, j int) bool: インデックス i の要素がインデックス j の要素よりも小さい場合に true を返します。
    • Swap(i, j int): インデックス ij の要素を入れ替えます。
  • sort.Sort 関数: sort パッケージの主要な関数で、sort.Interface を実装する任意のデータ構造をソートします。
  • multiSorter パターン: 複数のソートキー(例えば、ユーザー名でソートし、次に変更行数でソートするなど)に基づいてデータをソートするための一般的なパターンです。これは、sort.Interface を実装するカスタム型を作成し、複数の lessFunc (比較関数) をカプセル化することで実現されます。
  • Example 関数: Go言語のテストパッケージ (testing) における特別な関数で、ドキュメントの一部として表示され、実行可能な例として機能します。これらは、コードの動作を説明し、ユーザーがライブラリをどのように使用するかを示すために使用されます。

技術的詳細

このコミットは、multiSorterSort メソッドと OrderedBy コンストラクタの間のデータの受け渡しに関する論理的な不整合を修正しています。

元のコードでは、multiSorter 構造体は changes という []Change 型のスライスをフィールドとして持っていました。OrderedBy 関数は multiSorter のインスタンスを生成する際に、この changes フィールドを初期化しようとしていましたが、OrderedBy 関数自体は changes スライスを引数として受け取っていませんでした。

// Old code in OrderedBy
func OrderedBy(less ...lessFunc) *multiSorter {
 	return &multiSorter{
 		changes: changes, // 'changes' is not defined in this scope, likely a copy-paste error or misunderstanding
 		less:    less,
 	}
}

この問題は、multiSorter.Sort(changes []Change) メソッドが引数として changes スライスを受け取るにもかかわらず、その引数を無視して ms.changes フィールド(初期化されていないか、古いデータを持つ可能性がある)を使用していたことでさらに悪化していました。

このコミットによる修正は以下の2点です。

  1. multiSorter.Sort メソッドの修正: func (ms *multiSorter) Sort(changes []Change) メソッド内で、引数として渡された changes スライスを ms.changes フィールドに代入するように変更されました。これにより、multiSorter インスタンスがソート対象の正しいスライスを持つことが保証されます。

    // New code in multiSorter.Sort
    func (ms *multiSorter) Sort(changes []Change) {
    	ms.changes = changes // Now correctly assigns the passed slice
    	sort.Sort(ms)
    }
    
  2. OrderedBy コンストラクタの修正: OrderedBy 関数から changes: changes, の行が削除されました。これは、OrderedBymultiSorter のインスタンスを生成する際に changes スライスを初期化する責任を持たないことを明確にします。ソート対象のスライスは、multiSorter.Sort メソッドが呼び出される際に明示的に渡されるべきです。

    // New code in OrderedBy
    func OrderedBy(less ...lessFunc) *multiSorter {
    	return &multiSorter{
    		// changes: changes, // Removed
    		less: less,
    	}
    }
    
  3. Example_sortMultiKeys の呼び出し修正: Example_sortMultiKeys 関数内で、sort.Sort(OrderedBy(user, increasingLines)) のような直接的な sort.Sort の呼び出しが削除され、代わりに OrderedBy(user, increasingLines).Sort(changes) のように、multiSorter インスタンスの Sort メソッドを呼び出し、ソート対象の changes スライスを明示的に渡す形式に変更されました。これにより、例が multiSorter の正しい使用方法を反映するようになりました。

これらの変更により、multiSorter の設計がより明確になり、Example_sortMultiKeysmultiSorter を使用して複数のキーでソートを行う正しい方法を示すようになりました。

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

--- a/src/pkg/sort/example_multi_test.go
+++ b/src/pkg/sort/example_multi_test.go
@@ -26,6 +26,7 @@ type multiSorter struct {
 
 // Sort sorts the argument slice according to the less functions passed to OrderedBy.
 func (ms *multiSorter) Sort(changes []Change) {
+\tms.changes = changes
 \tsort.Sort(ms)
 }
 
@@ -33,8 +34,7 @@ func (ms *multiSorter) Sort(changes []Change) {
 // Call its Sort method to sort the data.
 func OrderedBy(less ...lessFunc) *multiSorter {
 \treturn &multiSorter{
-\t\tchanges: changes,
-\t\tless:    less,
+\t\tless: less,
 \t}\n }
 
@@ -108,11 +108,10 @@ func Example_sortMultiKeys() {
 	OrderedBy(user).Sort(changes)
 	fmt.Println("By user:", changes)
 
-\t// multiSorter implements the Sort interface, so we can also do this.\n-\tsort.Sort(OrderedBy(user, increasingLines))\n+\t// More examples.\n+\tOrderedBy(user, increasingLines).Sort(changes)\n \tfmt.Println("By user,<lines:", changes)
 
-\t// More examples.\n \tOrderedBy(user, decreasingLines).Sort(changes)
 \tfmt.Println("By user,>lines:", changes)
 

コアとなるコードの解説

  1. func (ms *multiSorter) Sort(changes []Change) 内の変更: + ms.changes = changes この行が追加されたことで、multiSorterSort メソッドが呼び出された際に、引数として渡された changes スライスが multiSorter 構造体の changes フィールドに正しく代入されるようになりました。これにより、multiSortersort.Interface を実装する際に内部で参照するデータが、ソート対象の最新のスライスであることが保証されます。

  2. func OrderedBy(less ...lessFunc) *multiSorter 内の変更: - changes: changes, この行が削除されました。これは、OrderedBy 関数が multiSorter インスタンスを初期化する際に、ソート対象の changes スライスを直接設定する責任を持たないことを明確にします。changes スライスは、Sort メソッドが呼び出される際に渡されるべきであり、OrderedBy はソートの比較ロジック (less 関数) の設定にのみ焦点を当てるべきです。

  3. func Example_sortMultiKeys() 内の変更: - // multiSorter implements the Sort interface, so we can also do this. - sort.Sort(OrderedBy(user, increasingLines)) + // More examples. + OrderedBy(user, increasingLines).Sort(changes) この変更は、Example_sortMultiKeys の中で multiSorter を使用してソートを行う方法を修正しています。以前は、OrderedBy が返す multiSorter インスタンスを直接 sort.Sort に渡していましたが、これは multiSorterchanges フィールドが正しく初期化されていないため、期待通りに動作しませんでした。 新しいコードでは、OrderedBy(user, increasingLines)multiSorter インスタンスを作成した後、そのインスタンスの Sort メソッドを呼び出し、ソート対象の changes スライスを明示的に渡しています。これにより、例が multiSorter の正しい使用パターンを反映し、ソートが期待通りに機能するようになります。コメントもより適切に「More examples.」に変更されています。

これらの変更は、multiSorter の設計と使用方法に関する誤解を解消し、sort パッケージのドキュメントとテストの正確性を向上させるものです。

関連リンク

参考にした情報源リンク