[インデックス 15502] ファイルの概要
このコミットは、Go言語の標準ライブラリ内のテストファイルにおいて、go vetツールによって発見されたprintfスタイルのフォーマット文字列の引数に関するバグを修正するものです。具体的には、fmt.Errorf関数内で使用されているフォーマット動詞が、対応する引数の型と一致していない箇所が修正されています。これにより、実行時の予期せぬ出力や、go vetによる警告が解消され、コードの堅牢性と正確性が向上します。
コミット
commit 1bf66f081fb34893235a02b29a8eb559e17c248e
Author: Rob Pike <r@golang.org>
Date: Thu Feb 28 11:33:08 2013 -0800
all: fix a few more printf arg bugs found by go vet
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7413045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1bf66f081fb34893235a02b29a8eb559e17c248e
元コミット内容
このコミットは、Go言語の標準ライブラリの以下の3つのテストファイルにおけるprintfフォーマット文字列の誤りを修正しています。
src/pkg/math/big/rat_test.gosrc/pkg/reflect/set_test.gosrc/pkg/strings/strings_test.go
修正内容は、fmt.Errorfなどのフォーマット関数で使用されている動詞(例: %b, %p, %s)が、対応する引数の型と合致するように変更することです。これにより、go vetツールが検出する警告が解消され、より正確なデバッグ出力が得られるようになります。
変更の背景
Go言語には、コードの潜在的なバグや疑わしい構造を検出するための静的解析ツールであるgo vetが存在します。このツールは、特にfmtパッケージのprintfスタイルの関数呼び出しにおいて、フォーマット動詞と引数の型が一致しないといった一般的な誤りを検出する能力を持っています。
このコミットが行われた背景には、go vetがGo標準ライブラリ内の既存のコードベースをスキャンし、いくつかのprintf引数に関するバグ(または潜在的な問題)を特定したことがあります。これらの問題は、プログラムのクラッシュを引き起こすものではないかもしれませんが、誤った出力や、開発者が意図しない動作につながる可能性がありました。特にテストコードにおいては、正確なエラーメッセージはデバッグの効率に直結するため、これらの修正は重要です。
Rob Pike氏(Go言語の共同開発者の一人)によるこのコミットは、go vetの検出結果に基づき、これらのフォーマットの不整合を修正し、Go言語の標準ライブラリ全体の品質と堅牢性を向上させることを目的としています。
前提知識の解説
1. Go言語のfmtパッケージとprintfスタイルフォーマット
Go言語のfmtパッケージは、フォーマットされたI/O(入出力)を実装するための機能を提供します。C言語のprintf関数に似た機能を提供し、様々なデータ型を文字列として整形して出力することができます。
fmtパッケージの主な関数には以下のようなものがあります。
fmt.Printf: 標準出力にフォーマットされた文字列を出力します。fmt.Sprintf: フォーマットされた文字列を返します。fmt.Errorf: フォーマットされたエラー文字列を返します。
これらの関数は、フォーマット文字列(例: "Value: %d")と、その後に続く引数を取ります。フォーマット文字列内の%で始まる部分は「フォーマット動詞」と呼ばれ、対応する引数をどのように整形するかを指示します。
主要なフォーマット動詞の例:
%v: 引数のデフォルトのフォーマット。任意の型に対応。%T: 引数の型を出力。%t: ブール値をtrueまたはfalseとして出力。%b: 整数を2進数で出力。%d: 整数を10進数で出力。%x,%X: 整数を16進数で出力。%f,%F,%e,%E,%g,%G: 浮動小数点数を様々な形式で出力。%s: 文字列を出力。%q: 文字列を二重引用符で囲み、Go構文でエスケープされた形式で出力。%p: ポインタの値を16進数で出力(0xプレフィックス付き)。%#v: Go構文で表現可能な形式で値を出力。構造体などの中身も表示される。
フォーマット動詞と引数の型が一致しない場合、コンパイルエラーにはならないことが多いですが、実行時に予期せぬ出力(例: %!t(bool=true)のようなエラーメッセージ)や、場合によってはパニックを引き起こす可能性があります。
2. go vetツール
go vetは、Go言語のソースコードを静的に解析し、潜在的なバグや疑わしい構造を報告するツールです。GoのSDKに標準で含まれており、go vet ./...のように実行することで、現在のモジュール内のすべてのパッケージを検査できます。
go vetが検出する一般的な問題には以下のようなものがあります。
printfフォーマット文字列の誤り: 本コミットの主題。フォーマット動詞と引数の型の不一致。- 構造体タグの誤り:
json:"field_name"のような構造体タグの構文エラー。 - ロックの誤用:
sync.Mutexなどのミューテックスのロック/アンロックの不整合。 - 到達不能なコード:
return文の後に続くコードなど、決して実行されないコード。 - 未使用の変数やインポート: コンパイラが警告するものの、
go vetがより詳細なコンテキストで報告する場合がある。
go vetは、コンパイラが検出できないが、実行時に問題を引き起こす可能性のある「疑わしい」コードパターンを特定するのに非常に役立ちます。CI/CDパイプラインにgo vetを組み込むことで、コード品質を自動的に維持し、早期にバグを発見することができます。
技術的詳細
このコミットの技術的詳細は、Go言語のfmtパッケージにおけるフォーマット動詞の厳密な適用と、go vetによる静的解析の有効性を示しています。
1. src/pkg/math/big/rat_test.goの修正
元のコード:
t.Errorf("Rat.SetString(%q).Float64().exact = %b, want %b", input, exact, wasExact)
修正後:
t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
ここでは、exactとwasExactというブール型の変数を表示するために、元のコードでは%b(2進数)が使用されていました。しかし、ブール値をtrueまたはfalseとして表示する正しいフォーマット動詞は%tです。%bは整数を2進数で表示するために使用されます。go vetは、ブール型に対して%bが使用されていることを検出し、警告を発しました。%tへの変更により、出力がより意図通りで読みやすくなります。
2. src/pkg/reflect/set_test.goの修正
元のコード(複数箇所で同様の修正):
t.Errorf("#5 MapIndex(b1) = %p want %p", p, b2)
修正後:
t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2)
この修正は、ポインタの表示に関するものです。
%p: ポインタの値を16進数で表示します(例:0xc000012000)。%#x:0xプレフィックス付きの16進数で表示します。これは主に整数型に対して使用されますが、uintptrのようなポインタを数値として扱う場合にも適切です。
pはuintptr型(ポインタを整数として表現したもの)であり、b2はポインタ型です。
元のコードでは両方に%pを使用していましたが、uintptrに対して%pを使用すると、go vetは警告を発する可能性があります。uintptrはポインタのアドレスを保持する整数型であり、その値を16進数で表示するには%xまたは%#xがより適切です。特に%#xは0xプレフィックスを付けてくれるため、ポインタのアドレスであることが視覚的に明確になります。
この修正により、uintptr型のpは%#xで、実際のポインタ型のb2は引き続き%pで表示され、それぞれの型に合った正確なフォーマットが適用されます。
3. src/pkg/strings/strings_test.goの修正
元のコード:
t.Errorf("ContainsRune(%s, %s) = %v, want %v",
ct.str, ct.r, !ct.expected, ct.expected)
修正後:
t.Errorf("ContainsRune(%q, %q) = %v, want %v",
ct.str, ct.r, !ct.expected, ct.expected)
ここでは、文字列ct.strとルーン(Unicodeコードポイント)ct.rを表示するために、元のコードでは%s(文字列)が使用されていました。
%s: 文字列をそのまま表示します。%q: 文字列を二重引用符で囲み、Go構文でエスケープされた形式で表示します。これは、文字列に特殊文字(例: 改行、タブ)が含まれている場合や、文字列の開始と終了を明確にしたい場合に非常に有用です。特にテストのエラーメッセージでは、どの文字列が問題を引き起こしたのかを正確に把握するために、%qが推奨されます。
ct.rはルーン型(runeはint32のエイリアス)ですが、fmtパッケージはrune型を%qでフォーマットすると、単一引用符で囲まれた文字リテラルとして表示します(例: 'a', '\n')。これは、文字列や文字のデバッグ出力において、その内容をより明確に表現するために非常に有効です。
この修正は、テストのエラーメッセージの可読性と正確性を向上させ、デバッグを容易にするためのものです。
コアとなるコードの変更箇所
このコミットは、Go言語の標準ライブラリ内の以下の3つのテストファイルに影響を与えています。
-
src/pkg/math/big/rat_test.goTestFloat64SpecialCases関数内のt.Errorf呼び出しで、ブール値のフォーマット動詞を%bから%tに変更。
--- a/src/pkg/math/big/rat_test.go +++ b/src/pkg/math/big/rat_test.go @@ -753,7 +753,7 @@ func TestFloat64SpecialCases(t *testing.T) { // 4. Check exactness using slow algorithm. if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact { - t.Errorf("Rat.SetString(%q).Float64().exact = %b, want %b", input, exact, wasExact) + t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact) } } } -
src/pkg/reflect/set_test.goTestImplicitMapConversion関数内の複数のt.Errorf呼び出しで、uintptr型のポインタ値を表示するフォーマット動詞を%pから%#xに変更。
--- a/src/pkg/reflect/set_test.go +++ b/src/pkg/reflect/set_test.go @@ -81,7 +81,7 @@ func TestImplicitMapConversion(t *testing.T) { if t.Failed() { t.Errorf("#5 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) } - if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) { - t.Errorf("#5 MapIndex(b1) = %p want %p", p, b2) + if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) { + t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2) } } { @@ -96,7 +96,7 @@ func TestImplicitMapConversion(t *testing.T) { if t.Failed() { t.Errorf("#6 after SetMapIndex(c1, c2): %p (!= %p), %t (map=%v)", x, c2, ok, m) } - if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() { - t.Errorf("#6 MapIndex(c1) = %p want %p", p, c2) + if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() { + t.Errorf("#6 MapIndex(c1) = %#x want %p", p, c2) } } { @@ -115,7 +115,7 @@ func TestImplicitMapConversion(t *testing.T) { if t.Failed() { t.Errorf("#7 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) } - if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) { - t.Errorf("#7 MapIndex(b1) = %p want %p", p, b2) + if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) { + t.Errorf("#7 MapIndex(b1) = %#x want %p", p, b2) } } -
src/pkg/strings/strings_test.goTestContainsRune関数内のt.Errorf呼び出しで、文字列とルーンのフォーマット動詞を%sから%qに変更。
--- a/src/pkg/strings/strings_test.go +++ b/src/pkg/strings/strings_test.go @@ -967,7 +967,7 @@ var ContainsRuneTests = []struct { func TestContainsRune(t *testing.T) { for _, ct := range ContainsRuneTests { if ContainsRune(ct.str, ct.r) != ct.expected { - t.Errorf("ContainsRune(%s, %s) = %v, want %v", + t.Errorf("ContainsRune(%q, %q) = %v, want %v", ct.str, ct.r, !ct.expected, ct.expected) } }
コアとなるコードの解説
このコミットのコアとなる変更は、Go言語のfmtパッケージにおけるフォーマット動詞の適切な使用に集約されます。各変更は、go vetが検出した特定の型とフォーマット動詞の不一致を解消し、より正確で意図通りのデバッグ出力を生成することを目的としています。
-
src/pkg/math/big/rat_test.go:- 変更前:
t.Errorf("... = %b, want %b", ..., exact, wasExact) - 変更後:
t.Errorf("... = %t, want %t", ..., exact, wasExact) exactとwasExactはブール型(bool)です。%bは整数を2進数でフォーマットするための動詞であり、ブール値には不適切です。%tはブール値をtrueまたはfalseとしてフォーマットするための正しい動詞です。この修正により、エラーメッセージがより明確で、誤解の余地がなくなります。
- 変更前:
-
src/pkg/reflect/set_test.go:- 変更前:
t.Errorf("... = %p want %p", p, b2) - 変更後:
t.Errorf("... = %#x want %p", p, b2) - ここで
pはuintptr型(ポインタのアドレスを保持する整数型)であり、b2は実際のポインタ型です。 %pはポインタ型に対して使用されるのが一般的です。uintptrは整数型であるため、%pを使用するとgo vetが警告を出すことがあります。%#xは、0xプレフィックス付きの16進数で整数をフォーマットします。uintptrのようなアドレス値を表示する際には、これがより適切で、かつgo vetの警告を回避できます。b2は引き続きポインタ型であるため、%pが適切に維持されています。この変更は、型のセマンティクスに合わせたフォーマットの厳密な適用を示しています。
- 変更前:
-
src/pkg/strings/strings_test.go:- 変更前:
t.Errorf("ContainsRune(%s, %s) = %v, want %v", ct.str, ct.r, ...) - 変更後:
t.Errorf("ContainsRune(%q, %q) = %v, want %v", ct.str, ct.r, ...) ct.strは文字列型、ct.rはルーン型(runeはint32のエイリアス)です。%sは文字列をそのまま出力しますが、文字列に空白や特殊文字が含まれる場合、どこからどこまでが文字列なのかが分かりにくくなることがあります。%qは、文字列を二重引用符で囲み、Go構文でエスケープされた形式で出力します。これにより、文字列の内容が明確になり、特にデバッグ時に文字列の境界や特殊文字の有無を正確に把握できます。ルーン型に対して%qを使用すると、単一引用符で囲まれた文字リテラルとして表示され、これもまたデバッグの助けとなります。
- 変更前:
これらの修正は、Go言語のfmtパッケージのベストプラクティスに従い、go vetのような静的解析ツールを活用してコード品質を向上させる典型的な例です。テストコードにおける正確なエラーメッセージは、将来のデバッグ作業の効率に大きく貢献します。
関連リンク
- Go言語
fmtパッケージのドキュメント: https://pkg.go.dev/fmt go vetコマンドのドキュメント: https://pkg.go.dev/cmd/vet- Go Code Review Comments -
Printfformat strings: https://go.dev/doc/effective_go#printf
参考にした情報源リンク
- 上記のGo言語公式ドキュメント
go vetに関する一般的な情報源(Goコミュニティのブログや記事など)- Go言語の
fmtパッケージのフォーマット動詞に関する一般的な知識 - コミットメッセージと差分から読み取れる情報
[インデックス 15502] ファイルの概要
このコミットは、Go言語の標準ライブラリ内のテストファイルにおいて、go vetツールによって発見されたprintfスタイルのフォーマット文字列の引数に関するバグを修正するものです。具体的には、fmt.Errorf関数内で使用されているフォーマット動詞が、対応する引数の型と一致していない箇所が修正されています。これにより、実行時の予期せぬ出力や、go vetによる警告が解消され、コードの堅牢性と正確性が向上します。
コミット
commit 1bf66f081fb34893235a02b29a8eb559e17c248e
Author: Rob Pike <r@golang.org>
Date: Thu Feb 28 11:33:08 2013 -0800
all: fix a few more printf arg bugs found by go vet
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7413045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1bf66f081fb34893235a02b29a8eb559e17c248e
元コミット内容
このコミットは、Go言語の標準ライブラリの以下の3つのテストファイルにおけるprintfフォーマット文字列の誤りを修正しています。
src/pkg/math/big/rat_test.gosrc/pkg/reflect/set_test.gosrc/pkg/strings/strings_test.go
修正内容は、fmt.Errorfなどのフォーマット関数で使用されている動詞(例: %b, %p, %s)が、対応する引数の型と合致するように変更することです。これにより、go vetツールが検出する警告が解消され、より正確なデバッグ出力が得られるようになります。
変更の背景
Go言語には、コードの潜在的なバグや疑わしい構造を検出するための静的解析ツールであるgo vetが存在します。このツールは、特にfmtパッケージのprintfスタイルの関数呼び出しにおいて、フォーマット動詞と引数の型が一致しないといった一般的な誤りを検出する能力を持っています。
このコミットが行われた背景には、go vetがGo標準ライブラリ内の既存のコードベースをスキャンし、いくつかのprintf引数に関するバグ(または潜在的な問題)を特定したことがあります。これらの問題は、プログラムのクラッシュを引き起こすものではないかもしれませんが、誤った出力や、開発者が意図しない動作につながる可能性がありました。特にテストコードにおいては、正確なエラーメッセージはデバッグの効率に直結するため、これらの修正は重要です。
Rob Pike氏(Go言語の共同開発者の一人)によるこのコミットは、go vetの検出結果に基づき、これらのフォーマットの不整合を修正し、Go言語の標準ライブラリ全体の品質と堅牢性を向上させることを目的としています。
前提知識の解説
1. Go言語のfmtパッケージとprintfスタイルフォーマット
Go言語のfmtパッケージは、フォーマットされたI/O(入出力)を実装するための機能を提供します。C言語のprintf関数に似た機能を提供し、様々なデータ型を文字列として整形して出力することができます。
fmtパッケージの主な関数には以下のようなものがあります。
fmt.Printf: 標準出力にフォーマットされた文字列を出力します。fmt.Sprintf: フォーマットされた文字列を返します。fmt.Errorf: フォーマットされたエラー文字列を返します。
これらの関数は、フォーマット文字列(例: "Value: %d")と、その後に続く引数を取ります。フォーマット文字列内の%で始まる部分は「フォーマット動詞」と呼ばれ、対応する引数をどのように整形するかを指示します。
主要なフォーマット動詞の例:
%v: 引数のデフォルトのフォーマット。任意の型に対応。%T: 引数の型を出力。%t: ブール値をtrueまたはfalseとして出力。%b: 整数を2進数で出力。%d: 整数を10進数で出力。%x,%X: 整数を16進数で出力。%f,%F,%e,%E,%g,%G: 浮動小数点数を様々な形式で出力。%s: 文字列を出力。%q: 文字列を二重引用符で囲み、Go構文でエスケープされた形式で出力。%p: ポインタの値を16進数で出力(0xプレフィックス付き)。%#v: Go構文で表現可能な形式で値を出力。構造体などの中身も表示される。
フォーマット動詞と引数の型が一致しない場合、コンパイルエラーにはならないことが多いですが、実行時に予期せぬ出力(例: %!t(bool=true)のようなエラーメッセージ)や、場合によってはパニックを引き起こす可能性があります。
2. go vetツール
go vetは、Go言語のソースコードを静的に解析し、潜在的なバグや疑わしい構造を報告するツールです。GoのSDKに標準で含まれており、go vet ./...のように実行することで、現在のモジュール内のすべてのパッケージを検査できます。
go vetが検出する一般的な問題には以下のようなものがあります。
printfフォーマット文字列の誤り: 本コミットの主題。フォーマット動詞と引数の型の不一致。- 構造体タグの誤り:
json:"field_name"のような構造体タグの構文エラー。 - ロックの誤用:
sync.Mutexなどのミューテックスのロック/アンロックの不整合。 - 到達不能なコード:
return文の後に続くコードなど、決して実行されないコード。 - 未使用の変数やインポート: コンパイラが警告するものの、
go vetがより詳細なコンテキストで報告する場合がある。
go vetは、コンパイラが検出できないが、実行時に問題を引き起こす可能性のある「疑わしい」コードパターンを特定するのに非常に役立ちます。CI/CDパイプラインにgo vetを組み込むことで、コード品質を自動的に維持し、早期にバグを発見することができます。
技術的詳細
このコミットの技術的詳細は、Go言語のfmtパッケージにおけるフォーマット動詞の厳密な適用と、go vetによる静的解析の有効性を示しています。
1. src/pkg/math/big/rat_test.goの修正
元のコード:
t.Errorf("Rat.SetString(%q).Float64().exact = %b, want %b", input, exact, wasExact)
修正後:
t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
ここでは、exactとwasExactというブール型の変数を表示するために、元のコードでは%b(2進数)が使用されていました。しかし、ブール値をtrueまたはfalseとして表示する正しいフォーマット動詞は%tです。%bは整数を2進数で表示するために使用されます。go vetは、ブール型に対して%bが使用されていることを検出し、警告を発しました。%tへの変更により、出力がより意図通りで読みやすくなります。
2. src/pkg/reflect/set_test.goの修正
元のコード(複数箇所で同様の修正):
t.Errorf("#5 MapIndex(b1) = %p want %p", p, b2)
修正後:
t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2)
この修正は、ポインタの表示に関するものです。
%p: ポインタの値を16進数で表示します(例:0xc000012000)。%#x:0xプレフィックス付きの16進数で表示します。これは主に整数型に対して使用されますが、uintptrのようなポインタを数値として扱う場合にも適切です。
pはuintptr型(ポインタを整数として表現したもの)であり、b2はポインタ型です。
元のコードでは両方に%pを使用していましたが、uintptrに対して%pを使用すると、go vetは警告を発する可能性があります。uintptrはポインタのアドレスを保持する整数型であり、その値を16進数で表示するには%xまたは%#xがより適切です。特に%#xは0xプレフィックスを付けてくれるため、ポインタのアドレスであることが視覚的に明確になります。
この修正により、uintptr型のpは%#xで、実際のポインタ型のb2は引き続き%pで表示され、それぞれの型に合った正確なフォーマットが適用されます。
3. src/pkg/strings/strings_test.goの修正
元のコード:
t.Errorf("ContainsRune(%s, %s) = %v, want %v",
ct.str, ct.r, !ct.expected, ct.expected)
修正後:
t.Errorf("ContainsRune(%q, %q) = %v, want %v",
ct.str, ct.r, !ct.expected, ct.expected)
ここでは、文字列ct.strとルーン(Unicodeコードポイント)ct.rを表示するために、元のコードでは%s(文字列)が使用されていました。
%s: 文字列をそのまま表示します。%q: 文字列を二重引用符で囲み、Go構文でエスケープされた形式で表示します。これは、文字列に特殊文字(例: 改行、タブ)が含まれている場合や、文字列の開始と終了を明確にしたい場合に非常に有用です。特にテストのエラーメッセージでは、どの文字列が問題を引き起こしたのかを正確に把握するために、%qが推奨されます。
ct.rはルーン型(runeはint32のエイリアス)ですが、fmtパッケージはrune型を%qでフォーマットすると、単一引用符で囲まれた文字リテラルとして表示します(例: 'a', '\n')。これは、文字列や文字のデバッグ出力において、その内容をより明確に表現するために非常に有効です。
この修正は、テストのエラーメッセージの可読性と正確性を向上させ、デバッグを容易にするためのものです。
コアとなるコードの変更箇所
このコミットは、Go言語の標準ライブラリ内の以下の3つのテストファイルに影響を与えています。
-
src/pkg/math/big/rat_test.goTestFloat64SpecialCases関数内のt.Errorf呼び出しで、ブール値のフォーマット動詞を%bから%tに変更。
--- a/src/pkg/math/big/rat_test.go +++ b/src/pkg/math/big/rat_test.go @@ -753,7 +753,7 @@ func TestFloat64SpecialCases(t *testing.T) { // 4. Check exactness using slow algorithm. if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact { - t.Errorf("Rat.SetString(%q).Float64().exact = %b, want %b", input, exact, wasExact) + t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact) } } } -
src/pkg/reflect/set_test.goTestImplicitMapConversion関数内の複数のt.Errorf呼び出しで、uintptr型のポインタ値を表示するフォーマット動詞を%pから%#xに変更。
--- a/src/pkg/reflect/set_test.go +++ b/src/pkg/reflect/set_test.go @@ -81,7 +81,7 @@ func TestImplicitMapConversion(t *testing.T) { if t.Failed() { t.Errorf("#5 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) } - if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) { - t.Errorf("#5 MapIndex(b1) = %p want %p", p, b2) + if p := mv.MapIndex(ValueOf(b1)).Elem().Pointer(); p != uintptr(unsafe.Pointer(b2)) { + t.Errorf("#5 MapIndex(b1) = %#x want %p", p, b2) } } { @@ -96,7 +96,7 @@ func TestImplicitMapConversion(t *testing.T) { if t.Failed() { t.Errorf("#6 after SetMapIndex(c1, c2): %p (!= %p), %t (map=%v)", x, c2, ok, m) } - if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() { - t.Errorf("#6 MapIndex(c1) = %p want %p", p, c2) + if p := mv.MapIndex(ValueOf(c1)).Pointer(); p != ValueOf(c2).Pointer() { + t.Errorf("#6 MapIndex(c1) = %#x want %p", p, c2) } } { @@ -115,7 +115,7 @@ func TestImplicitMapConversion(t *testing.T) { if t.Failed() { t.Errorf("#7 after SetMapIndex(b1, b2): %p (!= %p), %t (map=%v)", x, b2, ok, m) } - if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) { - t.Errorf("#7 MapIndex(b1) = %p want %p", p, b2) + if p := mv.MapIndex(ValueOf(b1)).Pointer(); p != uintptr(unsafe.Pointer(b2)) { + t.Errorf("#7 MapIndex(b1) = %#x want %p", p, b2) } } -
src/pkg/strings/strings_test.goTestContainsRune関数内のt.Errorf呼び出しで、文字列とルーンのフォーマット動詞を%sから%qに変更。
--- a/src/pkg/strings/strings_test.go +++ b/src/pkg/strings/strings_test.go @@ -967,7 +967,7 @@ var ContainsRuneTests = []struct { func TestContainsRune(t *testing.T) { for _, ct := range ContainsRuneTests { if ContainsRune(ct.str, ct.r) != ct.expected { - t.Errorf("ContainsRune(%s, %s) = %v, want %v", + t.Errorf("ContainsRune(%q, %q) = %v, want %v", ct.str, ct.r, !ct.expected, ct.expected) } }
コアとなるコードの解説
このコミットのコアとなる変更は、Go言語のfmtパッケージにおけるフォーマット動詞の適切な使用に集約されます。各変更は、go vetが検出した特定の型とフォーマット動詞の不一致を解消し、より正確で意図通りのデバッグ出力を生成することを目的としています。
-
src/pkg/math/big/rat_test.go:- 変更前:
t.Errorf("... = %b, want %b", ..., exact, wasExact) - 変更後:
t.Errorf("... = %t, want %t", ..., exact, wasExact) exactとwasExactはブール型(bool)です。%bは整数を2進数でフォーマットするための動詞であり、ブール値には不適切です。%tはブール値をtrueまたはfalseとしてフォーマットするための正しい動詞です。この修正により、エラーメッセージがより明確で、誤解の余地がなくなります。
- 変更前:
-
src/pkg/reflect/set_test.go:- 変更前:
t.Errorf("... = %p want %p", p, b2) - 変更後:
t.Errorf("... = %#x want %p", p, b2) - ここで
pはuintptr型(ポインタのアドレスを保持する整数型)であり、b2は実際のポインタ型です。 %pはポインタ型に対して使用されるのが一般的です。uintptrは整数型であるため、%pを使用するとgo vetが警告を出すことがあります。%#xは、0xプレフィックス付きの16進数で整数をフォーマットします。uintptrのようなアドレス値を表示する際には、これがより適切で、かつgo vetの警告を回避できます。b2は引き続きポインタ型であるため、%pが適切に維持されています。この変更は、型のセマンティクスに合わせたフォーマットの厳密な適用を示しています。
- 変更前:
-
src/pkg/strings/strings_test.go:- 変更前:
t.Errorf("ContainsRune(%s, %s) = %v, want %v", ct.str, ct.r, ...) - 変更後:
t.Errorf("ContainsRune(%q, %q) = %v, want %v", ct.str, ct.r, ...) ct.strは文字列型、ct.rはルーン型(runeはint32のエイリアス)です。%sは文字列をそのまま出力しますが、文字列に空白や特殊文字が含まれる場合、どこからどこまでが文字列なのかが分かりにくくなることがあります。%qは、文字列を二重引用符で囲み、Go構文でエスケープされた形式で出力します。これにより、文字列の内容が明確になり、特にデバッグ時に文字列の境界や特殊文字の有無を正確に把握できます。ルーン型に対して%qを使用すると、単一引用符で囲まれた文字リテラルとして表示され、これもまたデバッグの助けとなります。
- 変更前:
これらの修正は、Go言語のfmtパッケージのベストプラクティスに従い、go vetのような静的解析ツールを活用してコード品質を向上させる典型的な例です。テストコードにおける正確なエラーメッセージは、将来のデバッグ作業の効率に大きく貢献します。
関連リンク
- Go言語
fmtパッケージのドキュメント: https://pkg.go.dev/fmt go vetコマンドのドキュメント: https://pkg.go.dev/cmd/vet- Go Code Review Comments -
Printfformat strings: https://go.dev/doc/effective_go#printf
参考にした情報源リンク
- 上記のGo言語公式ドキュメント
- コミットメッセージと差分から読み取れる情報