[インデックス 11040] ファイルの概要
このコミットは、Go言語の様々な箇所における出力(print
)関連の不具合を修正するものです。具体的には、エラーログのフォーマット文字列の修正、fmt.Fprintln
からfmt.Fprintf
への変更、そしてfmt.Sprintf
のテストケースにおけるフォーマット文字列と引数の不一致の解消が含まれます。
コミット
commit a3baccefd6851acc77beadd645d5b0278146fe1d
Author: Robert Hencke <robert.hencke@gmail.com>
Date: Thu Jan 5 18:38:01 2012 -0800
various: fix prints
R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5516049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a3baccefd6851acc77beadd645d5b0278146fe1d
元コミット内容
various: fix prints
R=golang-dev, gri
CC=golang-dev
https://golang.org/cl/5516049
変更の背景
このコミットは、Go言語の標準ライブラリやツール、ダッシュボード関連のコードベースにおいて、文字列のフォーマットや出力に関する既存の軽微なバグや不整合を修正することを目的としています。特に、エラーメッセージが正しく表示されない問題や、fmt
パッケージの関数が意図した通りに動作しないテストケースの修正が含まれています。これらの修正は、コードの堅牢性を高め、デバッグ時の情報提供を改善し、テストの正確性を保証するために行われました。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語の基本的な概念とfmt
パッケージの知識が必要です。
fmt
パッケージ: Go言語におけるフォーマットI/Oを扱う標準パッケージです。C言語のprintf
やscanf
に似た機能を提供し、様々なデータ型を文字列に変換したり、文字列からデータをパースしたりするために使用されます。fmt.Errorf
: エラーオブジェクトを生成するための関数です。fmt.Sprintf
と同様にフォーマット文字列と引数を受け取り、フォーマットされたエラーメッセージを持つerror
型の値を返します。fmt.Fprintln
: 指定されたio.Writer
に引数をスペースで区切り、最後に改行を追加して出力する関数です。fmt.Fprintf
: 指定されたio.Writer
にフォーマット文字列と引数に基づいてフォーマットされた文字列を出力する関数です。printf
スタイルのフォーマット動詞(例:%v
,%s
,%d
など)を使用できます。fmt.Sprintf
: 引数をフォーマット文字列に基づいて整形し、その結果を新しい文字列として返す関数です。fmt.Fprintf
と同様にフォーマット動詞を使用します。
- フォーマット動詞 (
%v
,%x
,%s
など):fmt
パッケージの関数で使用されるプレースホルダーです。%v
: 値をデフォルトのフォーマットで出力します。任意の型に対応します。%x
: 整数を16進数で出力します。%s
: 文字列を出力します。
appengine.Context
: Google App EngineのGo SDKで使用されるコンテキストオブジェクトです。リクエスト固有の情報(ログ、データストアなど)にアクセスするために使用されます。datastore.NewKey
,datastore.Get
: Google App EngineのデータストアAPIの一部で、エンティティのキーを生成したり、データストアからエンティティを取得したりするために使用されます。testing.InternalTest
: Goのテストフレームワークで使用される内部構造体で、テスト関数とその名前を保持します。
技術的詳細
このコミットは、主にGo言語のfmt
パッケージの利用方法に関する3つの異なる修正を含んでいます。
-
misc/dashboard/app/build/notify.go
におけるエラーログの修正:- 元のコードでは、
c.Errorf("finding Log record %v: err", r.LogHash, err)
となっていました。ここで、err
という文字列リテラルがフォーマット文字列に含まれていましたが、実際にはerr
変数の内容を出力したかったと考えられます。 - 修正後のコード
c.Errorf("finding Log record %v: %v", r.LogHash, err)
では、2つ目の%v
プレースホルダーが追加され、err
変数の値が正しくフォーマットされてエラーメッセージに含められるようになりました。これにより、ログメッセージがより詳細で有用なものになります。
- 元のコードでは、
-
src/cmd/gotest/gotest.go
におけるFprintln
からFprintf
への変更:- 元のコードでは
fmt.Fprintln(b, "var tests = []testing.InternalTest{\\n")
が使用されていました。Fprintln
は引数をスペースで区切り、最後に改行を追加します。しかし、この場合、出力する文字列"var tests = []testing.InternalTest{\\n"
自体にすでに改行文字\n
が含まれています。 - 修正後のコード
fmt.Fprintf(b, "var tests = []testing.InternalTest{\\n")
では、Fprintf
が使用されています。Fprintf
はフォーマット文字列をそのまま解釈し、引数をフォーマット動詞に従って整形します。この変更は、冗長な改行の追加を防ぎ、より意図通りの出力を行うためのものです。また、将来的にこの行にフォーマット動詞を追加する可能性を考慮すると、Fprintf
の方が柔軟性があります。
- 元のコードでは
-
src/pkg/fmt/fmt_test.go
におけるSprintf
テストケースの修正:- 元のテストケースでは、
Sprintf("%x", 7, 112)
のように、フォーマット文字列が"%x"
(1つの引数に対応)であるにもかかわらず、2つの引数(7
,112
)が渡されていました。Goのfmt
パッケージの関数は、フォーマット文字列に指定されたプレースホルダーの数よりも多くの引数が渡された場合、余分な引数を無視します。このため、テストの意図(2つの値を16進数でフォーマットする)が正しく検証されていませんでした。 - 修正後のテストケース
Sprintf("%x %x", 7, 112)
では、フォーマット文字列が"%x %x"
に変更され、2つの引数に対応する2つのプレースホルダーが提供されています。これにより、7
と112
の両方が正しく16進数としてフォーマットされ、テストケースが意図した動作を正確に検証できるようになりました。
- 元のテストケースでは、
これらの変更は、Go言語のコードベースにおける出力処理の正確性と堅牢性を向上させるための、細かではあるが重要な修正です。
コアとなるコードの変更箇所
misc/dashboard/app/build/notify.go
--- a/misc/dashboard/app/build/notify.go
+++ b/misc/dashboard/app/build/notify.go
@@ -119,7 +119,7 @@ func sendFailMail(c appengine.Context, com *Commit, builder string) {
k := datastore.NewKey(c, "Log", r.LogHash, 0, nil)
l := new(Log)
if err := datastore.Get(c, k, l); err != nil {
- c.Errorf("finding Log record %v: err", r.LogHash, err)
+ c.Errorf("finding Log record %v: %v", r.LogHash, err)
return
}
src/cmd/gotest/gotest.go
--- a/src/cmd/gotest/gotest.go
+++ b/src/cmd/gotest/gotest.go
@@ -401,7 +401,7 @@ func writeTestmainGo() {
fmt.Fprintln(b) // for gofmt
// Tests.
- fmt.Fprintln(b, "var tests = []testing.InternalTest{\\n")
+ fmt.Fprintf(b, "var tests = []testing.InternalTest{\\n")
for _, f := range files {
for _, t := range f.tests {
fmt.Fprintf(b, "\\t{\"%s.%s\", %s.%s},\\n\", f.pkg, t, renamedPackage(f.pkg), t)
src/pkg/fmt/fmt_test.go
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -517,7 +517,7 @@ var mallocTest = []struct {
{1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
{1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
{2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
- {1, `Sprintf("%x %x")`, func() { Sprintf("%x", 7, 112) }},
+ {1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
{1, `Sprintf("%g")`, func() { Sprintf("%g", 3.14159) }},
{0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
{1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
コアとなるコードの解説
misc/dashboard/app/build/notify.go
の変更
この変更は、Google App Engineのデータストアからログレコードを取得する際にエラーが発生した場合のログ出力の修正です。
元のコードでは、エラーメッセージのフォーマット文字列に"err"
というリテラル文字列が含まれており、err
変数の内容が正しく出力されていませんでした。
修正後は、%v
というフォーマット動詞を使用することで、err
変数の実際の値(エラーの詳細)がログメッセージに埋め込まれるようになり、デバッグ時の情報が格段に向上しました。
src/cmd/gotest/gotest.go
の変更
この変更は、gotest
コマンドがテストメインファイル(_testmain.go
)を生成する際に、testing.InternalTest
スライスの宣言部分を書き出す処理に関するものです。
元のコードではfmt.Fprintln
を使用していましたが、これは引数をスペースで区切り、最後に改行を追加します。しかし、出力する文字列自体にすでに改行文字\n
が含まれているため、冗長な改行が発生する可能性がありました。
fmt.Fprintf
への変更により、フォーマット文字列がより直接的に解釈され、意図しない追加の改行を防ぎます。これは、コード生成の正確性を高めるための微調整です。
src/pkg/fmt/fmt_test.go
の変更
この変更は、fmt
パッケージのSprintf
関数のテストケースにおけるバグ修正です。
元のテストケースでは、Sprintf("%x", 7, 112)
のように、フォーマット文字列"%x"
が1つの引数しか期待していないにもかかわらず、2つの引数7
と112
が渡されていました。Goのfmt
パッケージは、フォーマット動詞の数と引数の数が一致しない場合、余分な引数を無視します。このため、112
はフォーマットされず、テストの意図が正しく検証されていませんでした。
修正後は、フォーマット文字列をSprintf("%x %x", 7, 112)
のように"%x %x"
に変更することで、2つの引数に対応する2つのフォーマット動詞が提供され、7
と112
の両方が正しく16進数としてフォーマットされるようになりました。これにより、テストケースがSprintf
の正しい動作を正確に検証できるようになりました。
関連リンク
- Go言語の
fmt
パッケージに関する公式ドキュメント: https://pkg.go.dev/fmt - Go言語の
testing
パッケージに関する公式ドキュメント: https://pkg.go.dev/testing - Google App Engine Go SDKの
appengine
パッケージに関するドキュメント (当時のバージョン): https://cloud.google.com/appengine/docs/standard/go/reference/appengine (現在のドキュメントは変更されている可能性があります)
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコード
- Go言語の
fmt
パッケージの動作に関する一般的な知識 - Go言語のテストの書き方に関する一般的な知識
- Google App EngineのGo SDKに関する一般的な知識