[インデックス 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) フォーマットに関する情報(テストコードの文脈から推測)