[インデックス 18904] ファイルの概要
このコミットは、Go言語の標準ライブラリであるfmtパッケージにおいて、浮動小数点数および複素数の書式設定(フォーマット)において、フォーマット動詞%Fを%fの同義語として扱われるように変更するものです。これにより、%fと同様に、指数表記ではなく小数点表記で数値を整形できるようになります。
コミット
- コミットハッシュ:
b00d967706377725b11acc16478e645ca7dd4431 - 作者: Rob Pike r@golang.org
- コミット日時: 2014年3月20日 木曜日 08:51:06 +1100
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b00d967706377725b11acc16478e645ca7dd4431
元コミット内容
fmt: make %F a synonym for %f
Rationale:
It already is for scanning.
It is accepted for complexes already, but doesn't work.
It's analogous to %G and %E.
C accepts it too, and we try to be roughly compatible.
Fixes #7518.
LGTM=bradfitz
R=golang-codereviews, bradfitz
CC=golang-codereviews
https://golang.org/cl/77580044
変更の背景
この変更は、Go言語のfmtパッケージにおける浮動小数点数および複素数のフォーマット動詞の整合性を向上させるために行われました。コミットメッセージに記載されている主な理由は以下の通りです。
- スキャン時との整合性:
fmtパッケージのScan関数群(例:fmt.Sscanf)では、既に%Fが%fの同義語として認識されていました。しかし、フォーマット(出力)時にはこの対応がされていなかったため、一貫性がありませんでした。 - 複素数型での挙動の修正: 複素数型(
complex64,complex128)のフォーマットにおいて、%Fは受け入れられていたものの、実際には正しく機能していませんでした。このコミットにより、複素数に対しても%Fが期待通りに動作するようになります。 %Gと%Eとの類似性:fmtパッケージには、%gと%G、%eと%Eのように、大文字と小文字で異なるフォーマット動詞が存在し、それぞれが特定の書式(例:%eは小文字のeを使った指数表記、%Eは大文字のEを使った指数表記)に対応しています。これに倣い、%f(小数点表記)に対して%Fを同義語とすることで、より直感的な命名規則に近づけます。- C言語との互換性: C言語の
printf関数では、%Fは%fの同義語として定義されています。Go言語のfmtパッケージはC言語のprintfに影響を受けている部分が多く、可能な限り互換性を保つことで、C言語の経験がある開発者にとって学習コストを低減し、期待通りの挙動を提供することを目指しています。
これらの理由から、GitHub Issue #7518で報告された問題に対応し、fmtパッケージのフォーマット動詞の挙動をより予測可能で一貫性のあるものにすることが目的です。
前提知識の解説
Go言語の fmt パッケージ
fmtパッケージは、Go言語におけるI/Oフォーマットを実装するためのパッケージです。C言語のprintfやscanfに似た機能を提供し、様々なデータ型を文字列に変換したり(フォーマット)、文字列からデータ型を解析したり(スキャン)することができます。
主な関数には以下のようなものがあります。
fmt.Printf: 標準出力にフォーマットされた文字列を出力します。fmt.Sprintf: フォーマットされた文字列を返します。fmt.Fprint: 指定されたio.Writerにフォーマットされた文字列を出力します。fmt.Scanf: 標準入力からフォーマットされたデータを読み取ります。fmt.Sscanf: 文字列からフォーマットされたデータを読み取ります。
フォーマット動詞(Verbs)
fmtパッケージでは、フォーマット文字列内で%に続く文字(フォーマット動詞)を使って、値の表示形式を指定します。
- 浮動小数点数(
float32,float64)のフォーマット動詞:%e: 指数表記(例:-1.234e+05)。小文字のeを使用。%E: 指数表記(例:-1.234E+05)。大文字のEを使用。%f: 小数点表記(例:123.456)。指数表記は使用しない。%g:%eまたは%fのうち、よりコンパクトな出力になる方を選択します。%G:%Eまたは%fのうち、よりコンパクトな出力になる方を選択します。
複素数(complex64, complex128)のフォーマット
Go言語の複素数型は、実部と虚部から構成されます。fmtパッケージで複素数をフォーマットする場合、通常は実部と虚部がそれぞれ浮動小数点数としてフォーマットされます。例えば、%fを使って複素数をフォーマットすると、(実部.xxx+虚部.yyyi)のような形式になります。
C言語の printf との関連
C言語の標準ライブラリにはprintf関数があり、Goのfmtパッケージと同様にフォーマット文字列と引数を使って出力を行います。C言語のprintfでは、浮動小数点数のフォーマットに%f, %e, %gなどが使われます。また、C99標準以降では、%Fが%fの同義語として導入されており、Goのfmtパッケージもこれに倣うことで、より広い互換性を提供しています。
技術的詳細
このコミットの技術的な詳細は、fmtパッケージの内部実装において、浮動小数点数および複素数のフォーマット処理を行う関数が、フォーマット動詞%fだけでなく%Fも受け入れるように変更された点にあります。
具体的には、以下のファイルが変更されています。
-
src/pkg/fmt/doc.go:fmtパッケージのドキュメントに、%Fが%fの同義語であることが明記されます。これは、ユーザーがfmtパッケージのドキュメントを参照した際に、%Fの挙動を理解できるようにするための変更です。
-
src/pkg/fmt/fmt_test.go:%Fが%fと同様に機能することを検証するための新しいテストケースが追加されます。これにより、変更が正しく実装され、将来のリグレッションを防ぐことができます。テストケースは、float32、float64、complex64、complex128の各型に対して%Fが期待通りの出力を生成するかを確認します。
-
src/pkg/fmt/format.go:- このファイルには、
fmtパッケージが内部的に使用するフォーマットロジックが含まれています。特に、fmt構造体のfmt_c64(complex64用)およびfmt_c128(complex128用)メソッドが変更されます。これらのメソッド内で、フォーマット動詞を処理するswitch文に'F'が追加され、'f'と同じ処理(小数点表記でのフォーマット)が実行されるようになります。
- このファイルには、
-
src/pkg/fmt/print.go:- このファイルには、
fmtパッケージのPrint系関数(Printfなど)が実際に値を文字列に変換する際の低レベルなロジックが含まれています。特に、pp構造体のfmtFloat32(float32用)およびfmtFloat64(float64用)メソッドが変更されます。これらのメソッド内で、フォーマット動詞を処理するswitch文に'F'が追加され、'f'と同じ処理(小数点表記でのフォーマット)が実行されるようになります。
- このファイルには、
これらの変更により、fmtパッケージは%Fを%fと全く同じように扱い、浮動小数点数や複素数を小数点表記でフォーマットする際に、大文字のFを使用しても期待通りの結果が得られるようになります。
コアとなるコードの変更箇所
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 7a7b63bd6b..7a14b80894 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -37,6 +37,7 @@
%e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456
+ %F synonym for %f
%g whichever of %e or %f produces more compact output
%G whichever of %E or %f produces more compact output
String and slice of bytes:
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 14a1a56c04..c7a09dedd9 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -220,6 +220,8 @@ var fmtTests = []struct {
{"%+.3e", 0.0, "+0.000e+00"},
{"%+.3e", 1.0, "+1.000e+00"},
{"%+.3f", -1.0, "-1.000"},
+ {"%+.3F", -1.0, "-1.000"},
+ {"%+.3F", float32(-1.0), "-1.000"},
{"%+07.2f", 1.0, "+001.00"},
{"%+07.2f", -1.0, "-001.00"},
{"% .3E", -1.0, "-1.000E+00"},
@@ -241,6 +243,8 @@ var fmtTests = []struct {
{"%+.3g", 1 + 2i, "(+1+2i)"},
{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
{"%.3f", 0i, "(0.000+0.000i)"},
+ {"%.3F", 0i, "(0.000+0.000i)"},
+ {"%.3F", complex64(0i), "(0.000+0.000i)"},
{"%.3g", 0i, "(0+0i)"},
{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
{"%.3f", 1 + 2i, "(1.000+2.000i)"},
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 3835aa9823..b0f4ad4b73 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -447,7 +447,7 @@ func (f *fmt) fmt_c64(v complex64, verb rune) {
case 'E':
f.fmt_E32(r)
case 'f':
- f.fmt_f32(r)
+ case 'f', 'F':
+ f.fmt_f32(r)
case 'g':
f.fmt_g32(r)
@@ -477,7 +477,7 @@ func (f *fmt) fmt_c128(v complex128, verb rune) {
case 'E':
f.fmt_E64(r)
case 'f':
- f.fmt_f64(r)
+ case 'f', 'F':
+ f.fmt_f64(r)
case 'g':
f.fmt_g64(r)
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 2f13bcd95e..c56d5b9401 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -447,7 +447,7 @@ func (p *pp) fmtFloat32(v float32, verb rune) {
p.fmt.fmt_e32(v)
case 'E':
p.fmt.fmt_E32(v)
- case 'f':
+ case 'f', 'F':
p.fmt.fmt_f32(v)
case 'g', 'v':
p.fmt.fmt_g32(v)
@@ -466,7 +466,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) {
p.fmt.fmt_e64(v)
case 'E':
p.fmt.fmt_E64(v)
- case 'f':
+ case 'f', 'F':
p.fmt.fmt_f64(v)
case 'g', 'v':
p.fmt.fmt_g64(v)
コアとなるコードの解説
src/pkg/fmt/doc.go の変更
- 追加行:
+ %F synonym for %f - 解説:
fmtパッケージの公式ドキュメントに、%Fが%fの同義語であることを明示的に追加しています。これにより、開発者がfmtパッケージのフォーマット動詞について調べた際に、%Fの挙動を正確に理解できるようになります。これは機能的な変更ではなく、ドキュメンテーションの改善です。
src/pkg/fmt/fmt_test.go の変更
- 追加行:
+ {"%+.3F", -1.0, "-1.000"},+ {"%+.3F", float32(-1.0), "-1.000"},+ {"%.3F", 0i, "(0.000+0.000i)"},+ {"%.3F", complex64(0i), "(0.000+0.000i)"},
- 解説:
fmtパッケージのテストスイートに、%Fフォーマット動詞の新しいテストケースが追加されています。- 最初の2つのテストケースは、
float64とfloat32の負の値に対して%+.3F(符号付き、小数点以下3桁、%Fフォーマット)が正しく-1.000とフォーマットされることを確認しています。 - 次の2つのテストケースは、
complex128とcomplex64のゼロ値に対して%.3F(小数点以下3桁、%Fフォーマット)が正しく(0.000+0.000i)とフォーマットされることを確認しています。 - これらのテストは、
%Fが%fと同じフォーマット結果を生成することを保証し、この変更が意図通りに機能していることを検証します。
- 最初の2つのテストケースは、
src/pkg/fmt/format.go の変更
- 変更箇所:
case 'f':がcase 'f', 'F':に変更。
- 解説: このファイルは、複素数型(
complex64とcomplex128)のフォーマット処理を担当するfmt_c64およびfmt_c128メソッドを含んでいます。変更前は、'f'というフォーマット動詞のみがfmt_f32(float32の実部/虚部をフォーマット)またはfmt_f64(float64の実部/虚部をフォーマット)を呼び出していましたが、この変更により'F'も同じ処理を呼び出すようになりました。これにより、複素数を%Fでフォーマットしようとした際に、正しく小数点表記で実部と虚部が整形されるようになります。
src/pkg/fmt/print.go の変更
- 変更箇所:
case 'f':がcase 'f', 'F':に変更。
- 解説: このファイルは、浮動小数点数型(
float32とfloat64)のフォーマット処理を担当するfmtFloat32およびfmtFloat64メソッドを含んでいます。変更前は、'f'というフォーマット動詞のみがfmt_f32またはfmt_f64を呼び出していましたが、この変更により'F'も同じ処理を呼び出すようになりました。これにより、浮動小数点数を%Fでフォーマットしようとした際に、正しく小数点表記で整形されるようになります。
これらのコード変更は、fmtパッケージの内部でフォーマット動詞を処理するswitch文に'F'を追加することで、%Fが%fと全く同じフォーマットロジックを共有するようにしています。これにより、コードの重複を避けつつ、%Fの新しい挙動を効率的に実装しています。
関連リンク
- Go Issue #7518: https://github.com/golang/go/issues/7518
参考にした情報源リンク
- Go fmtパッケージ ドキュメント: https://pkg.go.dev/fmt
- C言語 printf フォーマット指定子: (一般的なC言語のドキュメントを参照。例: cppreference.com, man page)
- Go Code Review 77580044: https://golang.org/cl/77580044 (コミットメッセージに記載されているGoのコードレビューリンク)
- 注:
golang.org/cl/のリンクは、GoのコードレビューシステムGerritへのリンクであり、現在はgo.googlesource.com/go/+/refs/changes/...のような形式にリダイレクトされることが多いです。 - この特定の変更セットは、https://go.googlesource.com/go/+/b00d967706377725b11acc16478e645ca7dd4431 で直接コミットとして参照できます。
- Gerritの変更セットID
77580044は、https://go-review.googlesource.com/c/go/+/77580044 で確認できます。
- 注: