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

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

このコミットは、Go言語の標準ライブラリ bytes パッケージ内の example_test.go ファイルに新しい例を追加するものです。具体的には、bytes.Compare 関数の適切な使用方法と、bytes.Equal 関数との使い分けについて、推奨されるパターンを示す例が追加されています。また、sort.Searchbytes.Compare を組み合わせてバイトスライスを検索する例も含まれています。

コミット

commit 56961274bbbdac59ab23af9ad592dfac89c94869
Author: Matthew Dempsky <mdempsky@google.com>
Date:   Mon Jan 7 09:59:37 2013 +1100

    bytes: Examples recommending bytes.Compare(a, b) rel_op 0 to test a rel_op b.
    
    R=golang-dev, minux.ma, rsc, adg
    CC=golang-dev
    https://golang.org/cl/7042045

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

https://github.com/golang/go/commit/56961274bbbdac59ab23af9ad592dfac89c94869

元コミット内容

bytes: Examples recommending bytes.Compare(a, b) rel_op 0 to test a rel_op b.

R=golang-dev, minux.ma, rsc, adg
CC=golang-dev
https://golang.org/cl/7042045

変更の背景

Go言語の bytes パッケージには、2つのバイトスライスを比較するための Compare 関数と Equal 関数が存在します。Compare 関数は、2つのバイトスライスの辞書順での比較結果を整数で返します(a < b なら負の値、a == b なら0、a > b なら正の値)。一方、Equal 関数は、2つのバイトスライスが等しいかどうかをブール値で返します。

開発者がこれらの関数を使用する際、特に等価性(==!=)の比較において bytes.Compare(a, b) == 0 のように Compare を使用する傾向がありました。しかし、bytes.Equal は等価性比較に特化しており、通常は bytes.Compare よりも効率的です。また、Compare の戻り値が負、ゼロ、正のいずれかであるという性質から、a < ba >= b といった関係演算子を模倣する際に、bytes.Compare(a, b) < 0 のようにゼロと比較することが推奨されます。

このコミットは、これらの推奨される使用パターンを開発者に明確に示し、誤用を防ぐことを目的としています。特に、bytes.Compare を関係演算子(<, <=, >, >=)の代替として使用する方法と、等価性比較には bytes.Equal を優先すべきであることを、具体的なコード例を通じて示しています。これにより、コードの可読性とパフォーマンスの向上が期待されます。

前提知識の解説

Go言語の bytes パッケージ

bytes パッケージは、バイトスライスを操作するためのユーティリティ関数を提供します。文字列操作に似た機能が多く、特にバイナリデータの処理や、ネットワークプロトコル、ファイルI/Oなどで頻繁に利用されます。

  • func Compare(a, b []byte) int: 2つのバイトスライス ab を辞書順で比較します。

    • ab より小さい場合、負の整数を返します。
    • ab と等しい場合、0 を返します。
    • ab より大きい場合、正の整数を返します。 この関数は、bytes.Equal よりも遅い場合があります。
  • func Equal(a, b []byte) bool: 2つのバイトスライス ab が同じ長さで、かつ同じバイトシーケンスを含む場合に true を返します。それ以外の場合は false を返します。等価性比較に特化しており、通常 Compare よりも高速です。

Go言語の sort パッケージと sort.Search

sort パッケージは、スライスをソートするための関数を提供します。sort.Search は、ソートされたスライス内で特定の条件を満たす最小のインデックスを見つけるためのバイナリサーチ(二分探索)アルゴリズムを実装した関数です。

  • func Search(n int, f func(i int) bool) int: Search は、[0, n) の範囲で、f(i)true を返す最小のインデックス i を返します。f は、i が増加するにつれて false から true に変化するような単調関数である必要があります。つまり、f(0), ..., f(i-1)false であり、f(i), ..., f(n-1)true であると仮定されます。 もしそのような i が存在しない場合(つまり、すべての f(i)false の場合)、n を返します。 この関数は、ソートされたデータ構造から要素を効率的に検索する際に非常に有用です。

関係演算子と等価性演算子

  • 関係演算子: 2つの値の間の順序関係を比較します。例: < (より小さい), <= (以下), > (より大きい), >= (以上)。
  • 等価性演算子: 2つの値が等しいかどうかを比較します。例: == (等しい), != (等しくない)。

このコミットでは、bytes.Compare を関係演算子のように使う方法と、bytes.Equal を等価性演算子のように使う方法を明確に区別して推奨しています。

技術的詳細

このコミットは、src/pkg/bytes/example_test.go に2つの新しい例 ExampleCompareExampleCompare_search を追加することで、bytes.Compare および bytes.Equal の推奨される使用パターンを具体的に示しています。

ExampleCompare の詳細

この例では、bytes.Compare の戻り値をゼロと比較することで、2つのバイトスライス ab の間の関係(より小さい、以下、より大きい、以上)をどのようにテストするかを示しています。

  • bytes.Compare(a, b) < 0: ab より小さい場合。
  • bytes.Compare(a, b) <= 0: ab 以下の場合。
  • bytes.Compare(a, b) > 0: ab より大きい場合。
  • bytes.Compare(a, b) >= 0: ab 以上の場合。

さらに、等価性比較には bytes.Equal を優先すべきであることを強調しています。

  • bytes.Equal(a, b): ab と等しい場合。
  • !bytes.Equal(a, b): ab と等しくない場合。

これは、bytes.Equal が等価性チェックに最適化されており、通常 bytes.Compare よりも高速であるためです。

ExampleCompare_search の詳細

この例では、sort.Search 関数と bytes.Compare を組み合わせて、ソートされたバイトスライスのスライス(haystack)から特定のバイトスライス(needle)をバイナリサーチで検索する方法を示しています。

sort.Search の第2引数に渡される匿名関数 func(i int) bool は、needle <= haystack[i] という条件を評価します。この条件は bytes.Compare(needle, haystack[i]) <= 0 として表現されます。sort.Search はこの関数が true を返す最小のインデックス i を見つけます。

検索後、見つかったインデックス ihaystack の範囲内であり、かつ needlehaystack[i]bytes.Equal で等しいことを確認することで、目的のバイトスライスが見つかったかどうかを判断します。これは、sort.Search が返すインデックスが必ずしも正確な一致を指すとは限らず、条件を満たす最初の要素のインデックスを返すため、最終的な等価性チェックが必要となるためです。

この例は、bytes.Compare がソートや検索アルゴリズムにおける比較関数としてどのように利用できるかを示す良い実践例です。

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

変更は src/pkg/bytes/example_test.go ファイルに集中しており、以下の39行が追加されています。

--- a/src/pkg/bytes/example_test.go
+++ b/src/pkg/bytes/example_test.go
@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"sort"
 )
 
 func ExampleBuffer() {
@@ -27,3 +28,41 @@ func ExampleBuffer_reader() {
 \tio.Copy(os.Stdout, dec)
 \t// Output: Gophers rule!
 }\n+\n+func ExampleCompare() {\n+\t// Interpret Compare\'s result by comparing it to zero.\n+\tvar a, b []byte\n+\tif bytes.Compare(a, b) < 0 {\n+\t\t// a less b\n+\t}\n+\tif bytes.Compare(a, b) <= 0 {\n+\t\t// a less or equal b\n+\t}\n+\tif bytes.Compare(a, b) > 0 {\n+\t\t// a greater b\n+\t}\n+\tif bytes.Compare(a, b) >= 0 {\n+\t\t// a greater or equal b\n+\t}\n+\n+\t// Prefer Equal to Compare for equality comparisons.\n+\tif bytes.Equal(a, b) {\n+\t\t// a equal b\n+\t}\n+\tif !bytes.Equal(a, b) {\n+\t\t// a not equal b\n+\t}\n+}\n+\n+func ExampleCompare_search() {\n+\t// Binary search to find a matching byte slice.\n+\tvar needle []byte\n+\tvar haystack [][]byte // Assume sorted\n+\ti := sort.Search(len(haystack), func(i int) bool {\n+\t\t// Return needle <= haystack[i].\n+\t\treturn bytes.Compare(needle, haystack[i]) <= 0\n+\t})\n+\tif i < len(haystack) && bytes.Equal(needle, haystack[i]) {\n+\t\t// Found it!\n+\t}\n+}\n```

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

追加されたコードは、Goのテストフレームワークが提供する `Example` 関数として実装されています。`Example` 関数は、その名前が示すように、特定の関数やパッケージの使用方法を示すためのコード例です。`go test` コマンドを実行すると、これらの例がコンパイルされ、実行され、出力が期待される出力(`// Output:` コメントで指定)と一致するかどうかが検証されます。これにより、例が常に正しく動作することが保証されます。

### `ExampleCompare` 関数

この関数は、`bytes.Compare` の戻り値をゼロと比較することで、バイトスライスの大小関係を判断する方法を具体的に示しています。また、等価性比較には `bytes.Equal` を使用することを推奨しています。これは、`bytes.Equal` が等価性チェックに特化しており、通常より効率的であるためです。

### `ExampleCompare_search` 関数

この関数は、`sort.Search` と `bytes.Compare` を組み合わせて、ソートされたバイトスライスのスライスから特定のバイトスライスを効率的に検索する方法を示しています。`sort.Search` の比較関数として `bytes.Compare` を使用することで、バイトスライスの辞書順比較に基づいたバイナリサーチが実現されます。検索結果の検証には `bytes.Equal` が使用され、正確な一致が確認されます。

これらの例は、`bytes` パッケージの主要な比較関数を正しく、かつ効率的に使用するためのベストプラクティスを開発者に提供することを目的としています。

## 関連リンク

-   Go言語 `bytes` パッケージのドキュメント: [https://pkg.go.dev/bytes](https://pkg.go.dev/bytes)
-   Go言語 `sort` パッケージのドキュメント: [https://pkg.go.dev/sort](https://pkg.go.dev/sort)
-   このコミットのGo Gerrit Code Reviewリンク: [https://golang.org/cl/7042045](https://golang.org/cl/7042045)

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

-   Go言語の公式ドキュメント
-   Go言語のソースコード
-   Go言語のテストとExample関数に関する一般的な知識
-   バイナリサーチ(二分探索)アルゴリズムに関する一般的な知識