[インデックス 15343] ファイルの概要
このコミットは、Go言語の標準ライブラリ image/png パッケージ内のテストファイル reader_test.go における変更です。具体的には、テストコード内でファイルの読み込みに使用されていた bufio.Reader が bufio.Scanner に置き換えられ、それに伴い読み込みロジックが修正されています。
コミット
commit c6f23bb7c1cdc83cea7e0cec5c912a67d1b19988
Author: Rob Pike <r@golang.org>
Date: Wed Feb 20 15:57:18 2013 -0800
image/png: use Scanner in reader_test.
R=nigeltao
CC=golang-dev
https://golang.org/cl/7399044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c6f23bb7c1cdc83cea7e0cec5c912a67d1b19988
元コミット内容
image/png: use Scanner in reader_test.
このコミットは、image/png パッケージのテストコード reader_test.go において、bufio.Reader の代わりに bufio.Scanner を使用するように変更するものです。
変更の背景
この変更の背景には、Go言語の標準ライブラリにおけるI/O処理のベストプラクティスの進化があります。bufio.Reader は汎用的なバッファリングリーダーであり、ReadString などのメソッドを使って区切り文字(この場合は改行文字 \n)まで読み込むことができます。しかし、bufio.Scanner は、より高レベルで効率的なテキストスキャン(行単位、単語単位など)のために設計されています。
テストコード reader_test.go では、SNG (Simple Network Graphics) フォーマットのデータを生成し、それを読み込んで比較する処理が行われています。SNGフォーマットはテキストベースであり、行ごとにデータを処理することが一般的です。このような行指向の処理において、bufio.Scanner は bufio.Reader よりも簡潔で、エラーハンドリングも容易になるという利点があります。
具体的には、bufio.Reader.ReadString はエラーが発生した場合に部分的な文字列とエラーを返す可能性がありますが、bufio.Scanner は Scan() メソッドが false を返した後に Err() メソッドでエラーを確認するという、より明確なエラー報告メカニズムを提供します。これにより、テストコードの堅牢性と可読性が向上します。
前提知識の解説
Go言語の bufio パッケージ
bufio パッケージは、Go言語におけるバッファリングされたI/O操作を提供します。これにより、ディスクI/OやネットワークI/Oなどの低レベルなI/O操作の効率を向上させることができます。主な型として Reader と Scanner があります。
-
bufio.Reader:io.Readerインターフェースをラップし、バッファリング機能を追加します。- バイト単位、ルーン単位、行単位など、様々な粒度での読み込みメソッドを提供します。
ReadString(delim byte): 指定された区切り文字が出現するまでデータを読み込み、その文字列を返します。区切り文字も返される文字列に含まれます。エラーが発生した場合、部分的なデータとエラーを返すことがあります。ReadBytes(delim byte):ReadStringと同様ですが、バイトスライスを返します。
-
bufio.Scanner:io.Readerからデータを読み込み、指定された「スキャン関数」に基づいてトークン(行、単語など)に分割するためのユーティリティです。Scan(): 次のトークン(デフォルトでは次の行)を読み込みます。読み込みが成功した場合はtrueを、エラーが発生したかEOFに達した場合はfalseを返します。Text():Scan()がtrueを返した場合に、現在スキャンされたトークン(文字列)を返します。Bytes():Scan()がtrueを返した場合に、現在スキャンされたトークン(バイトスライス)を返します。Err():Scan()がfalseを返した場合に、発生したエラーを返します。EOFの場合はnilを返します。SetSplitFunc(split SplitFunc): トークンの分割方法をカスタマイズできます。
image/png パッケージ
Go言語の標準ライブラリ image/png パッケージは、PNG (Portable Network Graphics) 画像フォーマットのエンコードとデコードをサポートします。このパッケージは、PNGファイルの読み込み(デコード)と書き込み(エンコード)のための機能を提供し、image パッケージの Image インターフェースと連携して動作します。
テストにおけるSNGフォーマット
SNG (Simple Network Graphics) は、PNG画像をテキスト形式で表現するためのシンプルなフォーマットです。これは、PNGのバイナリデータを直接扱うのではなく、人間が読みやすいテキスト形式で画像データを記述することを目的としています。テストにおいては、SNGフォーマットを使用することで、PNG画像の生成と検証をより容易に行うことができます。テストコードでは、生成されたPNG画像をSNG形式に変換し、期待されるSNG出力と比較することで、エンコーダ/デコーダの正確性を検証しています。
技術的詳細
このコミットの主要な変更点は、reader_test.go 内の TestReader 関数における bufio.Reader から bufio.Scanner への移行です。
元のコードでは、bufio.NewReader を使用して io.Pipe やファイルからデータを読み込み、pb.ReadString('\n') や sb.ReadString('\n') を使って行単位でデータを取得していました。この ReadString メソッドは、改行文字が見つかるか、エラーが発生するか、EOFに達するまで読み込みを続けます。エラーハンドリングは、perr != nil や serr != nil で直接エラーをチェックする形で行われていました。
変更後のコードでは、bufio.NewScanner を使用しています。Scanner のループは pdone := pb.Scan() と sdone := sb.Scan() で制御されます。Scan() メソッドは、次のトークン(デフォルトでは行)が正常に読み込まれた場合に true を返します。ループの終了条件は、両方のスキャナが false を返した場合(つまり、両方ともEOFに達したかエラーが発生した場合)です。
エラーハンドリングも変更されています。Scanner では、Scan() が false を返した後に Err() メソッドを呼び出すことで、読み込み中に発生したエラーを確認します。EOFの場合は Err() は nil を返します。これにより、EOFと実際のエラーを明確に区別できるようになります。
また、行の取得は pb.Text() と sb.Text() を使用して行われます。これは Scan() が成功した後に呼び出され、スキャンされた行の文字列を返します。
この変更により、行単位の読み込みとエラーハンドリングのロジックがよりGo言語のイディオムに沿った形になり、コードの可読性と堅牢性が向上しています。特に、bufio.Scanner は内部でバッファリングを効率的に管理し、ReadString のように部分的な結果とエラーを同時に返すような複雑さを避けることができます。
コアとなるコードの変更箇所
変更は src/pkg/image/png/reader_test.go ファイルの TestReader 関数に集中しています。
--- a/src/pkg/image/png/reader_test.go
+++ b/src/pkg/image/png/reader_test.go
@@ -208,7 +208,7 @@ func TestReader(t *testing.T) {
}
piper, pipew := io.Pipe()
- pb := bufio.NewReader(piper)
+ pb := bufio.NewScanner(piper)
go sng(pipew, fn, img)
defer piper.Close()
@@ -219,7 +219,7 @@ func TestReader(t *testing.T) {
continue
}
defer sf.Close()
- sb := bufio.NewReader(sf)
+ sb := bufio.NewScanner(sf)
if err != nil {
t.Error(fn, err)
continue
@@ -227,24 +227,28 @@ func TestReader(t *testing.T) {
// Compare the two, in SNG format, line by line.
for {
-\t\t\tps, perr := pb.ReadString('\n')
-\t\t\tss, serr := sb.ReadString('\n')
-\t\t\tif perr == io.EOF && serr == io.EOF {
+\t\t\tpdone := pb.Scan()
+\t\t\tsdone := sb.Scan()
+\t\t\tif pdone && sdone {
\t\t\t\tbreak
\t\t\t}\n-\t\t\tif perr != nil {\n-\t\t\t\tt.Error(fn, perr)\n-\t\t\t\tbreak\n-\t\t\t}\n-\t\t\tif serr != nil {\n-\t\t\t\tt.Error(fn, serr)\n+\t\t\tif pdone || sdone {
+\t\t\t\tt.Errorf("%s: Different sizes", fn)
\t\t\t\tbreak
\t\t\t}\n+\t\t\tps := pb.Text()
+\t\t\tss := sb.Text()
\t\t\tif ps != ss {\
\t\t\t\tt.Errorf("%s: Mismatch\\n%sversus\\n%s\\n", fn, ps, ss)\
\t\t\t\tbreak
\t\t\t}\
\t\t}
+\t\tif pb.Err() != nil {
+\t\t\tt.Error(fn, pb.Err())
+\t\t}\
+\t\tif sb.Err() != nil {
+\t\t\tt.Error(fn, sb.Err())
+\t\t}\
\t}\
}
コアとなるコードの解説
-
bufio.NewReaderからbufio.NewScannerへの変更:pb := bufio.NewReader(piper)がpb := bufio.NewScanner(piper)に変更されました。sb := bufio.NewReader(sf)がsb := bufio.NewScanner(sf)に変更されました。 これにより、行単位の読み込みに特化したScannerの機能を利用できるようになります。
-
読み込みループの変更:
- 変更前:
ps, perr := pb.ReadString('\n')とss, serr := sb.ReadString('\n')を使って行を読み込み、perrやserrでエラーやEOFを直接チェックしていました。 - 変更後:
pdone := pb.Scan()とsdone := sb.Scan()を使って次の行の読み込みを試みます。Scan()は読み込みが成功したかどうかを示すブール値を返します。 - ループの終了条件も変更され、
if pdone && sdoneで両方のスキャナがまだ読み込み可能であればループを継続し、そうでなければbreakします。 if pdone || sdoneの条件は、片方のスキャナだけがEOFに達したかエラーになった場合(つまり、ファイルサイズが異なる場合)を検出するために追加されました。これは、テスト対象のSNGデータが同じサイズであることを期待しているためです。
- 変更前:
-
行データの取得方法の変更:
- 変更前:
psとssにはReadStringが返した文字列が直接格納されていました。 - 変更後:
ps := pb.Text()とss := sb.Text()を使って、Scan()が成功した後にスキャンされた行の文字列を取得します。
- 変更前:
-
エラーハンドリングの変更:
- 変更前は、
perr != nilやserr != nilでエラーを個別にチェックしていました。 - 変更後、ループの後に
if pb.Err() != nilとif sb.Err() != nilを追加し、スキャナの処理中に発生したエラーをまとめてチェックするようにしました。ScannerのErr()メソッドは、Scan()がfalseを返した原因がEOFではなく実際のエラーであった場合に、そのエラーを返します。
- 変更前は、
これらの変更により、テストコードは bufio.Scanner の提供するよりクリーンで効率的な行処理のイディオムに準拠するようになりました。
関連リンク
- Go言語
bufioパッケージのドキュメント: https://pkg.go.dev/bufio - Go言語
image/pngパッケージのドキュメント: https://pkg.go.dev/image/png - Go言語の
io.Pipeのドキュメント: https://pkg.go.dev/io#Pipe
参考にした情報源リンク
- Go言語の公式ドキュメント (
pkg.go.dev) - Go言語のソースコード (
github.com/golang/go) - Go言語における
bufio.Readerとbufio.Scannerの使い分けに関する一般的な情報源(例: 技術ブログ、Stack Overflowなど) - PNG (Portable Network Graphics) フォーマットの一般的な知識
- SNG (Simple Network Graphics) フォーマットに関する情報(テストコードの文脈から推測)