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

[インデックス 16597] ファイルの概要

このコミットは、Go言語の標準ライブラリmath/bigパッケージ内のテストファイルnat_test.goにおける書式指定子の誤りを修正するものです。具体的には、t.Errorf関数で使用されているフォーマット動詞が、出力される変数の型と一致していなかった点を修正しています。この問題はgo vetツールによって指摘されました。

コミット

commit 6154ae8e24f8e4ddc414cc8c11a5ac091935cb73
Author: Robert Griesemer <gri@golang.org>
Date:   Tue Jun 18 14:16:40 2013 -0700

    math/big: fix Errorf verb
    
    Pointed out by go vet.
    
    R=r
    CC=golang-dev
    https://golang.org/cl/10368048

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6154ae8e24f8e4ddc414cc8c11a5ac091935cb73

元コミット内容

src/pkg/math/big/nat_test.goファイルにおいて、runModWTests関数内のt.Errorf呼び出しで、rという変数を表示するために%s(文字列)フォーマット動詞が使用されていました。

--- a/src/pkg/math/big/nat_test.go
+++ b/src/pkg/math/big/nat_test.go
@@ -685,7 +685,7 @@ func runModWTests(t *testing.T, tests []modWTest) {
 
 		r := in.abs.modW(d.abs[0])
 		if r != out.abs[0] {
-			t.Errorf("#%d failed: got %s want %s", i, r, out)
+			t.Errorf("#%d failed: got %d want %s", i, r, out)
 		}
 	}
 }

変更の背景

この変更は、Go言語の静的解析ツールであるgo vetによって指摘された問題を修正するために行われました。go vetは、Goのソースコードを検査し、疑わしい構成要素や移植性のないコード、一般的なエラーなどを報告します。このケースでは、t.Errorfのフォーマット文字列と引数の型が一致していないという潜在的なバグを検出しました。具体的には、整数型の変数rに対して文字列のフォーマット動詞%sが使われていたため、実行時に予期せぬ出力やエラーが発生する可能性がありました。

前提知識の解説

math/bigパッケージ

math/bigパッケージは、Go言語で任意精度の算術演算(多倍長整数、有理数、浮動小数点数)を扱うための機能を提供します。通常のGoの組み込み型(int, int64など)では表現できない非常に大きな数値や、高い精度が求められる計算に使用されます。このパッケージは、暗号化、科学計算、金融アプリケーションなど、数値の精度が重要な場面で利用されます。

go vet

go vetは、Go言語のソースコードを静的に解析し、潜在的なバグや疑わしいコードパターンを検出するツールです。コンパイル時には検出されないが、実行時に問題を引き起こす可能性のあるエラー(例: Printf系の関数におけるフォーマット文字列と引数の不一致、到達不能なコード、ロックの誤用など)を特定するのに役立ちます。開発プロセスにgo vetを組み込むことで、コードの品質と信頼性を向上させることができます。

testing.T.Errorf

testing.Tは、Goのテストフレームワークで使用される型で、テストの実行状態を管理し、エラーやログメッセージを報告するためのメソッドを提供します。t.Errorfは、テスト中にエラーが発生した場合に、指定されたフォーマット文字列と引数を使用してエラーメッセージを整形し、テストを失敗としてマークする関数です。fmt.Printfと同様に、フォーマット動詞(例: %d%s%vなど)を使用して変数の値を整形して出力します。

フォーマット動詞

Go言語のfmtパッケージ(およびそれを使用するt.Errorfなどの関数)では、様々なフォーマット動詞が提供されており、変数の型に応じて適切なものを選択する必要があります。

  • %d: 整数値を10進数で表示します。
  • %s: 文字列を表示します。
  • %v: 値をデフォルトのフォーマットで表示します。任意の型に対して機能するため、デバッグなどで便利ですが、特定の型に対してはより具体的な動詞を使用することが推奨されます。

このコミットのケースでは、rが整数型であるにもかかわらず%sが使われていたため、go vetが警告を発しました。

技術的詳細

このコミットの技術的詳細は、t.Errorf関数のフォーマット文字列の正確な使用に集約されます。

元のコードでは、t.Errorf("#%d failed: got %s want %s", i, r, out)という行がありました。ここで、iはテストケースのインデックス(整数)、rin.abs.modW(d.abs[0])の結果(Nat型の要素、実質的にはWord型、つまり符号なし整数)、outは期待される結果(Nat型)です。

問題は、rが整数型(Word型はuintまたはuint64のエイリアス)であるにもかかわらず、その値を出力するために文字列フォーマット動詞%sが使用されていた点です。Goのfmtパッケージでは、%sは文字列型に対して使用されるべきであり、整数型に対して使用すると、コンパイルエラーにはならないものの、実行時に予期せぬ動作(例えば、数値が文字列として解釈されず、メモリ上のアドレスや内部表現が出力されるなど)を引き起こす可能性があります。

go vetはこのような型とフォーマット動詞の不一致を検出する能力を持っており、このケースで正確に問題を指摘しました。修正は、rのフォーマット動詞を%sから%dに変更することで、rが整数として正しく整形されて出力されるようにしました。これにより、テストのエラーメッセージがより正確で読みやすいものになります。

コアとなるコードの変更箇所

変更はsrc/pkg/math/big/nat_test.goファイルの1箇所のみです。

diff --git a/src/pkg/math/big/nat_test.go b/src/pkg/math/big/nat_test.go
index 2dd7bf6396..1d4dfe80d3 100644
--- a/src/pkg/math/big/nat_test.go
+++ b/src/pkg/math/big/nat_test.go
@@ -685,7 +685,7 @@ func runModWTests(t *testing.T, tests []modWTest) {
 
 		r := in.abs.modW(d.abs[0])
 		if r != out.abs[0] {
-			t.Errorf("#%d failed: got %s want %s", i, r, out)
+			t.Errorf("#%d failed: got %d want %s", i, r, out)
 		}
 	}
 }

具体的には、687行目のt.Errorf呼び出しにおいて、2番目のフォーマット動詞が%sから%dに変更されました。

コアとなるコードの解説

変更された行は、runModWTestsというテストヘルパー関数の中にあります。この関数は、math/bigパッケージのNat型(多倍長自然数)のモジュロ演算(modWメソッド)のテストを実行します。

func runModWTests(t *testing.T, tests []modWTest) {
	for i, test := range tests {
		in := test.in
		d := test.d
		out := test.out

		r := in.abs.modW(d.abs[0]) // r は Word 型 (uint または uint64) の結果
		if r != out.abs[0] {
			// 修正前: t.Errorf("#%d failed: got %s want %s", i, r, out)
			// 修正後: t.Errorf("#%d failed: got %d want %s", i, r, out)
			t.Errorf("#%d failed: got %d want %s", i, r, out)
		}
	}
}

ここで、rin.abs.modW(d.abs[0])の計算結果であり、これはWord型(Goのアーキテクチャに応じてuintまたはuint64のエイリアス)の値を返します。つまり、rは整数です。

元のコードでは、r%s(文字列)として出力しようとしていました。これは、rが整数であるため、型とフォーマット動詞の不一致を引き起こします。この不一致は、go vetによって「Errorf format string has %s for arg r of type math/big.Word」のような警告として報告されます。

修正後のコードでは、rのフォーマット動詞が%d(整数)に変更されました。これにより、rの値が正しく整数としてフォーマットされ、エラーメッセージに表示されるようになります。outNat型であり、%sまたは%vで適切に表示されるため、outに対するフォーマット動詞は変更されていません。

この修正は、コードの機能には影響を与えませんが、テストのエラー報告の正確性と信頼性を向上させ、go vetのような静的解析ツールからの警告を解消します。これは、Go言語のコードベース全体で品質を維持するための一般的なプラクティスの一部です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • go vetに関する一般的な情報源
  • fmtパッケージのフォーマット動詞に関する情報
  • Go言語のコミット履歴とコードレビューシステム (Gerrit/Go CL)
  • Go CL 10368048: https://golang.org/cl/10368048 (コミットメッセージに記載されているリンク)
  • Go言語のWord型に関する情報 (通常はsrc/math/big/arith.goなどで定義されている)