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

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

このコミットでは、src/pkg/exp/locale/collate/sort.gosrc/pkg/exp/locale/collate/sort_test.go の2つの新しいファイルが追加されています。これらのファイルは、Go言語の実験的なロケールパッケージである exp/locale/collate に、文字列のソート機能を追加するものです。

コミット

  • コミットハッシュ: 34b533cd81dbad155a8e2265d91110434bbac2fb
  • 作者: Marcel van Lohuizen mpvl@golang.org
  • 日付: 2013年1月23日 (水) 14:16:22 +0100

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

https://github.com/golang/go/commit/34b533cd81dbad155a8e2265d91110434bbac2fb

元コミット内容

    exp/locale/collate: added functionality for sorting.
    Eliminates the need for the user to fiddle with keys.

    R=rsc
    CC=golang-dev
    https://golang.org/cl/7060051

変更の背景

このコミットの主な背景は、Go言語の exp/locale/collate パッケージ(現在の golang.org/x/text/collate パッケージの前身)における文字列のソート処理の複雑さを軽減することにあります。以前は、ロケール固有のルールに従って文字列をソートするには、ユーザーが直接「照合キー(collation keys)」を生成し、それらを比較する必要がありました。このプロセスは、特にUnicodeの複雑な特性(アクセント、大文字小文字、文字幅など)を考慮に入れると、非常に煩雑でエラーが発生しやすいものでした。

コミットメッセージにある「Eliminates the need for the user to fiddle with keys.(ユーザーがキーをいじる必要をなくす)」という文言が示す通り、この変更の目的は、照合キーの生成と管理という低レベルな詳細を抽象化し、ユーザーがより高レベルなAPIを通じて直接文字列や文字列スライスをソートできるようにすることでした。これにより、国際化されたアプリケーションでの文字列ソートの実装が大幅に簡素化され、開発者の負担が軽減されます。

前提知識の解説

照合 (Collation)

照合とは、文字列を特定の順序で並べ替えるプロセスを指します。これは単に文字コードの順序で並べることとは異なり、言語や文化に固有のルール(ロケール)に基づいて行われます。例えば、ドイツ語では「ä」は「a」と「b」の間に来ることもあれば、「ae」として扱われることもあります。また、大文字と小文字の区別、アクセント記号の有無、文字幅(全角/半角)なども照合順序に影響を与えます。

照合キー (Collation Keys)

照合キーは、文字列の照合順序をバイト列で表現したものです。複雑なUnicode文字列の比較を効率的に行うために使用されます。文字列そのものを直接比較する代わりに、まず各文字列から照合キーを生成し、そのバイト列を辞書順に比較することで、正しい照合順序を決定します。照合キーは、元の文字列のすべての照合特性(アクセント、大文字小文字、文字幅など)をエンコードしており、バイト列として比較可能であるため、高速なソートや検索が可能になります。

exp/locale/collate パッケージは、Collator 型を提供し、この Collator が特定のロケールに基づいて照合キーを生成する機能を持っています。このコミット以前は、ユーザーは Collator.KeyCollator.KeyFromString メソッドを使って照合キーを生成し、それらをGo標準ライブラリの sort パッケージと組み合わせてソートロジックを自前で実装する必要がありました。

技術的詳細

このコミットでは、exp/locale/collate パッケージにソート機能が直接統合され、ユーザーが照合キーを直接扱う必要がなくなりました。これは主に src/pkg/exp/locale/collate/sort.go に追加された新しい型とメソッドによって実現されています。

sort.go の主要な要素

  1. swapper インターフェース:

    type swapper interface {
    	Swap(i, j int)
    }
    

    これはGo標準の sort.InterfaceSwap メソッドと同じシグネチャを持つシンプルなインターフェースです。sorter 構造体がソート対象のデータと連携するために使用されます。

  2. sorter 構造体:

    type sorter struct {
    	buf  *Buffer
    	keys [][]byte
    	src  swapper
    }
    

    この構造体は、ソート処理の内部状態を管理します。

    • buf: Collator が照合キーを生成する際に使用するバッファです。メモリ割り当てを削減するために再利用されます。
    • keys: 生成された照合キー(バイトスライス)を格納するスライスです。
    • src: ソート対象のデータが swapper インターフェースを満たす場合に、その Swap メソッドを呼び出すために使用されます。

    sortersort.Interface (Len, Less, Swap) を実装しており、Go標準の sort.Sort 関数に渡すことができます。

    • Len(): s.keys の長さを返します。
    • Less(i, j int) bool: s.keys[i]s.keys[j] をバイト比較し、s.keys[i]s.keys[j] より小さい場合に true を返します。これにより、照合キーの辞書順比較が実現されます。
    • Swap(i, j int): s.keys 内の要素を交換すると同時に、s.srcSwap メソッドを呼び出して、ソート対象の元のデータも交換します。
  3. Lister インターフェース:

    type Lister interface {
    	Len() int
    	Swap(i, j int)
    	// Bytes returns the bytes of the text at index i.
    	Bytes(i int) []byte
    }
    

    この新しいインターフェースは、Collator.Sort メソッドがソート可能な任意のデータ型を抽象化するために導入されました。Go標準の sort.InterfaceBytes(i int) []byte メソッドが追加された形です。この Bytes メソッドは、指定されたインデックスの文字列のバイト表現を返します。これにより、Collator はソート対象の文字列を取得し、それに対応する照合キーを生成できます。

  4. Collator の新しいメソッド:

    • func (c *Collator) Sort(x Lister): このメソッドは、Lister インターフェースを満たす任意のデータ構造を、cCollator インスタンス)の照合ルールに従ってソートします。内部的には、x の各要素から照合キーを生成し、それらを sorter に格納した後、sort.Sort(c.sorter) を呼び出してソートを実行します。sorterSwap メソッドが x.Swap を呼び出すことで、元のデータも適切に並べ替えられます。

    • func (c *Collator) Strings(x []string): このメソッドは、[]string 型のスライスを、c の照合ルールに従ってソートするための便利なラッパーです。内部的には、sort.StringSlice(x)Lister として扱い、Collator.Sort メソッドを呼び出します。これにより、一般的な文字列スライスのソートが非常に簡単になります。

sort_test.go

このファイルには、新しく追加されたソート機能のテストと使用例が含まれています。

  • ExampleCollator_Strings(): Collator.Strings メソッドを使用して文字列スライスをソートする簡単な例を示しています。
  • TestSort(): Lister インターフェースを実装したカスタム型 (sorter という名前だが、これはテスト用のヘルパー型で、collate パッケージ内の sorter 構造体とは別物) を定義し、Collator.Sort メソッドが正しく機能することを確認するテストです。

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

このコミットで追加された主要なコードは以下の2つのファイルです。

  1. src/pkg/exp/locale/collate/sort.go:

    • swapper インターフェースの定義
    • sorter 構造体の定義と sort.Interface の実装 (Len, Less, Swap メソッド)
    • Lister インターフェースの定義
    • Collator 型に Sort(x Lister) メソッドの追加
    • Collator 型に Strings(x []string) メソッドの追加
  2. src/pkg/exp/locale/collate/sort_test.go:

    • ExampleCollator_Strings() 関数(Collator.Strings の使用例)
    • テスト用の sorter 型(Lister インターフェースの実装例)
    • TestSort() 関数(Collator.Sort のテスト)

これらの追加により、exp/locale/collate パッケージは、照合キーを直接操作することなく、ロケール固有のソートを直接実行できる高レベルなAPIを提供するようになりました。

コアとなるコードの解説

このコミットの核心は、ユーザーが照合キーの生成と管理という複雑なタスクから解放されるように、ソートロジックを Collator 型の内部にカプセル化した点にあります。

Collator.Sort(x Lister) の動作

  1. Collator.Sort メソッドが Lister インターフェースを満たす x を引数として受け取ります。
  2. 内部で c.sorter.init(n) を呼び出し、ソートに必要な内部バッファとキーのスライスを初期化します。
  3. for ループで x の各要素 (i から n-1 まで) を反復処理します。
  4. 各要素について、c.sorter.keys[i] = c.Key(c.sorter.buf, x.Bytes(i)) を呼び出します。ここで c.KeyCollator の既存のメソッドであり、x.Bytes(i) からロケール固有の照合キーを生成し、それを c.sorter.keys スライスに格納します。c.sorter.buf はキー生成時のメモリ割り当てを最適化するためのバッファです。
  5. すべての照合キーが生成された後、c.sorter.sort(x) を呼び出します。この sort メソッドは、c.sorter 自身を sort.Sort 関数に渡し、xsortersrc フィールドに設定します。
  6. sort.Sortc.sorterLen, Less, Swap メソッドを呼び出してソートを実行します。
  7. 特に重要なのは c.sorter.Swap(i, j) メソッドです。このメソッドは、c.sorter.keys 内の照合キーを交換するだけでなく、c.src.Swap(i, j) を呼び出すことで、元のデータ (x) の要素も同時に交換します。これにより、照合キーの順序が元のデータの順序に反映されます。

Collator.Strings(x []string) の動作

このメソッドは []string 型に特化した便利なラッパーです。

  1. c.sorter.init(len(x)) を呼び出し、内部バッファとキーのスライスを初期化します。
  2. for ループで x の各文字列 s を反復処理します。
  3. c.sorter.keys[i] = c.KeyFromString(c.sorter.buf, s) を呼び出し、各文字列から照合キーを生成して格納します。
  4. c.sorter.sort(sort.StringSlice(x)) を呼び出します。ここで sort.StringSlice(x) は、Go標準ライブラリの sort パッケージが提供する []stringsort.Interface に適合させるためのアダプターです。このアダプターは swapper インターフェースも満たすため、c.sorter.sort に渡すことができます。

これらの変更により、開発者は collate.New("en").Strings(myStrings) のように、非常に直感的な方法でロケール固有の文字列ソートを実行できるようになりました。

関連リンク

参考にした情報源リンク