[インデックス 12951] ファイルの概要
このコミットは、Go言語の標準ライブラリの一部である2つのファイル、src/pkg/exp/norm/maketables.go
と src/pkg/text/template/parse/lex.go
に対する修正を含んでいます。これらの修正は、Go言語の静的解析ツールである go vet
によって検出されたエラーを解消することを目的としています。
src/pkg/exp/norm/maketables.go
: このファイルは、Unicode正規化に関連するテーブルを生成するための実験的なパッケージの一部です。具体的には、文字の正規化プロパティ、特にCanonical Combining Class (CCC) の検証ロジックが含まれています。src/pkg/text/template/parse/lex.go
: このファイルは、Goの標準テンプレートパッケージtext/template
の字句解析(lexing)部分を担当しています。テンプレート文字列をトークンに分割する処理を行います。
コミット
- コミットハッシュ:
459837c86ecf583ea7597b47b1d2591c332440c9
- 作者: Rob Pike r@golang.org
- 日付: 2012年4月25日 (水) 11:33:27 +1000
- 変更ファイル数: 2
- 変更行数: 3行の追加、3行の削除
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/459837c86ecf583ea7597b47b1d2591c332440c9
元コミット内容
all: fix errors found by go vet
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6125044
変更の背景
このコミットの主な背景は、Go言語の公式静的解析ツールである go vet
によって検出されたエラーを修正することです。go vet
は、Goプログラムの潜在的なバグや疑わしい構造を特定するために設計されており、コンパイルは通るものの、実行時に問題を引き起こす可能性のあるコードパターンを警告します。
具体的には、このコミットで修正されたエラーは、fmt
パッケージのフォーマット文字列における引数の型とフォーマット動詞の不一致、およびより詳細なデバッグ情報の提供に関するものです。go vet
は、fmt.Printf
や logger.Fatalf
のような関数呼び出しにおいて、フォーマット動詞(例: %U
, %d
)が対応する引数の型と一致しない場合に警告を発します。これにより、実行時に予期せぬ出力やパニックが発生するのを防ぎます。
このコミットは、コードの堅牢性とデバッグのしやすさを向上させるための、一般的なコード品質改善の一環として行われました。
前提知識の解説
go vet
ツール
go vet
は、Go言語のソースコードを静的に分析し、潜在的なエラーや疑わしい構造を報告するコマンドラインツールです。コンパイラが検出できないような、しかし実行時に問題を引き起こす可能性のあるバグパターン(例: Printf
フォーマット文字列の誤用、到達不能なコード、ロックの誤用など)を特定します。go vet
はGoのツールチェインの一部であり、Go開発者がコードの品質と信頼性を維持するために広く利用されています。
Go言語の fmt
パッケージとフォーマット動詞
Go言語の fmt
パッケージは、フォーマットされたI/O(入出力)を実装するための機能を提供します。fmt.Printf
や fmt.Errorf
、log.Fatalf
など、多くの関数がC言語の printf
に似たフォーマット文字列を使用します。フォーマット文字列には、引数をどのように表示するかを指示する「フォーマット動詞」が含まれます。
このコミットに関連する主なフォーマット動詞は以下の通りです。
%U
: UnicodeコードポイントをU+HHHH
形式で表示します。引数はrune
型(またはint
型でUnicodeコードポイントを表すもの)を期待します。%+U
:%U
と同じですが、常にU+HHHH
形式で表示します。%#U
: UnicodeコードポイントをU+HHHH 'c'
形式で表示します。HHHH
はコードポイントの16進数表現、'c'
はそのコードポイントに対応する文字です。これはデバッグ時に非常に有用で、コードポイントだけでなく、それがどの文字を表しているのかも一目で確認できます。引数はrune
型を期待します。%d
: 整数を10進数で表示します。引数は整数型を期待します。
go vet
は、例えば %U
が指定されているにもかかわらず、rune
型ではない int
型の引数が渡された場合などに警告を発します。これは、%U
が期待する形式で引数を解釈できないため、予期せぬ出力やエラーにつながる可能性があるためです。
Unicode正規化とCanonical Combining Class (CCC)
Unicode正規化は、異なるバイト列で表現されながらも同じ意味を持つ文字シーケンス(例: アクセント付き文字)を、一貫した単一の表現に変換するプロセスです。これにより、テキストの比較や検索が正確に行えるようになります。
Canonical Combining Class (CCC) は、Unicode文字のプロパティの一つで、結合文字(例: アクセント記号)が正規化中にどのように並べ替えられるかを決定します。CCCの値は0から255までの範囲で、0は結合文字ではない文字(基底文字)を示し、0以外の値は結合文字の結合順序を示します。src/pkg/exp/norm/maketables.go
は、このCCCを含むUnicodeのプロパティテーブルを生成するロジックを含んでおり、その検証中に go vet
のエラーが検出されました。
Goのテンプレートエンジンと字句解析
Goの text/template
パッケージは、データ構造をテキスト出力に変換するためのテンプレートエンジンを提供します。このエンジンは、テンプレート文字列を解析し、データと結合して最終的な出力を生成します。
字句解析(lexing)は、コンパイラやインタプリタの最初のフェーズであり、入力文字列(この場合はテンプレート文字列)を意味のある最小単位である「トークン」のシーケンスに分解するプロセスです。src/pkg/text/template/parse/lex.go
は、この字句解析器の実装を含んでおり、テンプレート内の文字を読み込み、エラーが発生した場合に報告する役割を担っています。
技術的詳細
このコミットは、go vet
が検出した2種類の問題を修正しています。
-
fmt.Printf
フォーマット動詞%U
の引数不一致の修正 (src/pkg/exp/norm/maketables.go
):src/pkg/exp/norm/maketables.go
のprintCharInfoTables
関数内で、logger.Fatalf
の呼び出しにおいて%U
フォーマット動詞が使用されていました。しかし、この%U
に渡されていた引数はcc
(Canonical Combining Class) というint
型の変数でした。%U
はUnicodeコードポイント(rune
型またはint
型でコードポイントを表すもの)を期待しますが、cc
は文字のプロパティ値であり、直接コードポイントを表すものではありません。go vet
はこの不一致を検出し、警告を発しました。修正では、cc
の代わりに、ループの現在の文字を表すr
(rune) を%U
の引数として渡すように変更されました。これにより、logger.Fatalf
の出力が、エラーが発生した文字のUnicodeコードポイントを正しく表示するようになり、デバッグ情報がより正確になりました。- 変更前:
logger.Fatalf("%U: ...", cc)
- 変更後:
logger.Fatalf("%U: ...", r, cc)
- 変更前:
-
fmt.Errorf
フォーマット動詞%+U
から%#U
への変更 (src/pkg/text/template/parse/lex.go
):src/pkg/text/template/parse/lex.go
のlexText
関数内で、l.errorf
の呼び出しにおいてbad character %+U
というフォーマット文字列が使用されていました。%+U
はU+HHHH
形式でUnicodeコードポイントを表示しますが、デバッグ時にはそのコードポイントが実際にどの文字を表しているのかも知りたい場合があります。go vet
は、%+U
の代わりに%#U
を使用することを推奨する場合があります。%#U
はU+HHHH 'c'
形式で、コードポイントとその文字表現の両方を出力します。これにより、エラーメッセージがより詳細になり、問題の文字を特定しやすくなります。この変更は、デバッグ情報の質を向上させるためのものです。- 変更前:
return l.errorf("bad character %+U", r)
- 変更後:
return l.errorf("bad character %#U", r)
- 変更前:
これらの変更は、Goのコードベース全体で go vet
の警告を解消し、コードの品質とデバッグの容易性を向上させるための、一般的なメンテナンス作業の一環です。
コアとなるコードの変更箇所
src/pkg/exp/norm/maketables.go
--- a/src/pkg/exp/norm/maketables.go
+++ b/src/pkg/exp/norm/maketables.go
@@ -607,10 +607,10 @@ func printCharInfoTables() int {
tccc := ccc(d[len(d)-1])
cc := ccc(r)
if cc != 0 && lccc == 0 && tccc == 0 {
- logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", cc)
+ logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc)
}
if tccc < lccc && lccc != 0 {
const msg = "%U: lccc (%d) must be <= tcc (%d)"
logger.Fatalf(msg, r, lccc, tccc)
}
if cc != lccc {
if cc != 0 {
- logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", cc)
+ logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc)
}
index = 3
}
src/pkg/text/template/parse/lex.go
--- a/src/pkg/text/template/parse/lex.go
+++ b/src/pkg/text/template/parse/lex.go
@@ -348,7 +348,7 @@ Loop:
l.backup()
word := l.input[l.start:l.pos]
if !l.atTerminator() {
- return l.errorf("bad character %+U", r)
+ return l.errorf("bad character %#U", r)
}
switch {
case key[word] > itemKeyword:
コアとなるコードの解説
src/pkg/exp/norm/maketables.go
の変更
// 変更前
logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", cc)
// 変更後
logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc)
この変更は、logger.Fatalf
の呼び出しにおけるフォーマット文字列の引数に関するものです。
- 変更前は、
%U
フォーマット動詞に対してcc
(Canonical Combining Class) というint
型の変数が渡されていました。cc
は文字の結合クラスを表す数値であり、Unicodeコードポイントそのものではありません。go vet
は、%U
が期待するrune
(Unicodeコードポイント) とcc
の型が一致しない、または意図しない使い方であると判断し、警告を発しました。 - 変更後は、
%U
の引数としてr
が追加されました。r
はループの現在のイテレーションで処理されているrune
(Unicodeコードポイント) です。これにより、%U
は正しく文字のコードポイントを表示し、%d
はcc
の値を表示するようになります。結果として、エラーメッセージが「どの文字で、その文字のCCCが何であるか」を正確に伝えるようになり、デバッグが容易になります。
同様の修正が、少し下の行でも行われています。
// 変更前
logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", cc)
// 変更後
logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc)
これも上記と同様に、%U
に r
を渡し、cc
を %d
に対応させることで、go vet
の警告を解消し、より正確なエラーメッセージを出力するように修正されています。
src/pkg/text/template/parse/lex.go
の変更
// 変更前
return l.errorf("bad character %+U", r)
// 変更後
return l.errorf("bad character %#U", r)
この変更は、l.errorf
の呼び出しにおけるフォーマット動詞の変更です。
- 変更前は
%+U
が使用されていました。これはUnicodeコードポイントをU+HHHH
の形式で表示します。 - 変更後は
%#U
に変更されました。これはUnicodeコードポイントをU+HHHH 'c'
の形式で表示します。ここで'c'
はそのコードポイントに対応する実際の文字です。 - この変更により、エラーメッセージに文字そのものが含まれるようになり、デバッグ時にどの文字が問題を引き起こしたのかを視覚的に、かつより明確に把握できるようになります。これは
go vet
が推奨する、より情報量の多いフォーマット動詞の使用例です。
関連リンク
- Go言語の
go vet
コマンド: https://pkg.go.dev/cmd/vet - Go言語の
fmt
パッケージ: https://pkg.go.dev/fmt - Go言語の
text/template
パッケージ: https://pkg.go.dev/text/template - Unicode正規化の概要 (Go言語の文脈): https://blog.golang.org/normalization (これはブログ記事であり、直接的なドキュメントではありませんが、関連情報として有用です)
参考にした情報源リンク
- Go言語の公式ドキュメント (上記「関連リンク」に記載の各パッケージドキュメント)
go vet
の使用例や解説を含むGoコミュニティの議論やブログ記事 (具体的なURLは特定していませんが、一般的な知識として参照しました)- UnicodeのCanonical Combining Class (CCC) に関する一般的な情報 (Unicode標準のドキュメントなど)
- Go言語の
fmt
パッケージのフォーマット動詞に関する情報 (特に%U
,%+U
,%#U
の違い)
これらの情報源は、go vet
の機能、fmt
パッケージのフォーマット動詞の挙動、および関連するGo言語の標準ライブラリのコンテキストを理解するために参照されました。