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

[インデックス 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言語のprintfscanfに似た機能を提供し、様々なデータ型を文字列に変換したり、文字列からデータをパースしたりするために使用されます。
    • 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つの異なる修正を含んでいます。

  1. 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変数の値が正しくフォーマットされてエラーメッセージに含められるようになりました。これにより、ログメッセージがより詳細で有用なものになります。
  2. 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の方が柔軟性があります。
  3. 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つのプレースホルダーが提供されています。これにより、7112の両方が正しく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つの引数7112が渡されていました。Goのfmtパッケージは、フォーマット動詞の数と引数の数が一致しない場合、余分な引数を無視します。このため、112はフォーマットされず、テストの意図が正しく検証されていませんでした。 修正後は、フォーマット文字列をSprintf("%x %x", 7, 112)のように"%x %x"に変更することで、2つの引数に対応する2つのフォーマット動詞が提供され、7112の両方が正しく16進数としてフォーマットされるようになりました。これにより、テストケースがSprintfの正しい動作を正確に検証できるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード
  • Go言語のfmtパッケージの動作に関する一般的な知識
  • Go言語のテストの書き方に関する一般的な知識
  • Google App EngineのGo SDKに関する一般的な知識