[インデックス 1483] ファイルの概要
このコミットは、Go言語の標準ライブラリであるfmt
パッケージにおける識別子の命名規則を広範囲にわたって変更するものです。具体的には、エクスポートされる(外部からアクセス可能な)識別子とエクスポートされない(内部利用のみの)識別子の区別を明確にするために、大文字・小文字の使い分け("casify")を適用しています。これにより、パッケージのAPIサーフェスがより整理され、内部実装の詳細が隠蔽されるようになります。
コミット
commit 497bb9c07d01bc4094d4831fe9211c64563643e4
Author: Rob Pike <r@golang.org>
Date: Thu Jan 15 15:40:27 2009 -0800
casify fmt and its dependents.
R=rsc
DELTA=224 (0 added, 2 deleted, 222 changed)
OCL=22875
CL=22875
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/497bb9c07d01bc4094d4831fe9211c64563643e4
元コミット内容
このコミットは、fmt
パッケージ内の関数、メソッド、定数、構造体、インターフェースなどの識別子について、そのエクスポート状態(公開APIか内部実装か)を明確にするために命名規則を変更しています。Go言語では、識別子の最初の文字が大文字である場合、それはエクスポートされ、パッケージ外部からアクセス可能です。一方、最初の文字が小文字である場合、それはエクスポートされず、パッケージ内部でのみ利用可能です。このコミットでは、この規則に従って多くの識別子の名前が変更されています。
変更の背景
Go言語の初期段階において、ライブラリのAPI設計は進化の途上にありました。fmt
パッケージは、Goプログラムにおける基本的なフォーマット済みI/Oを提供する非常に重要なパッケージです。このコミットが行われた2009年1月は、Go言語が一般に公開される前の開発初期段階にあたります。
この時期の変更の背景には、以下のような意図が考えられます。
- APIの明確化と安定化: パッケージの公開APIと内部実装を明確に区別することで、将来的なAPIの変更が内部実装の変更に影響されにくくなり、ユーザーが利用すべき機能とそうでない機能がはっきりします。これにより、APIの安定性が向上し、ユーザーは安心して
fmt
パッケージを利用できるようになります。 - カプセル化の強化: 内部の詳細を隠蔽し、外部からは必要な機能のみを提供することで、パッケージの保守性が向上します。開発者は内部実装を自由にリファクタリングでき、それが外部のコードに影響を与えるリスクを低減できます。
- Go言語の命名規則の徹底: Go言語の設計思想として、シンプルさと明確さが重視されます。識別子の大文字・小文字によるエクスポート制御は、その思想を反映したものです。このコミットは、この重要な命名規則を
fmt
パッケージ全体に徹底的に適用し、コードベースの一貫性を高めることを目的としています。特に、Fmt
型に関連するメソッドにFmt_
プレフィックスを付与することで、そのメソッドがFmt
型のフォーマット機能に特化していることを示唆し、APIの意図をより明確にしています。
前提知識の解説
Go言語のパッケージとエクスポートルール
Go言語では、コードは「パッケージ」という単位で整理されます。パッケージは、関連する機能の集合体であり、再利用可能なコードのモジュール化を促進します。
Go言語には、他の言語とは異なる独特のエクスポートルールがあります。
- エクスポートされる識別子(Exported Identifiers): 識別子(変数、関数、型、メソッドなど)の最初の文字が大文字で始まる場合、その識別子はパッケージの外部に「エクスポート」されます。つまり、他のパッケージからその識別子を参照し、利用することができます。これは、そのパッケージの公開APIの一部となります。
- エクスポートされない識別子(Unexported Identifiers): 識別子の最初の文字が小文字で始まる場合、その識別子はパッケージの内部でのみ利用可能です。他のパッケージからは直接アクセスすることはできません。これらは、パッケージの内部実装の詳細であり、外部に公開すべきではない機能やデータ構造に使用されます。
このルールは、Go言語におけるカプセル化の基本的なメカニズムであり、APIの設計において非常に重要です。
fmt
パッケージの役割
fmt
パッケージは、Go言語におけるフォーマット済みI/O(入出力)を実装するためのパッケージです。C言語のprintf
やscanf
に似た機能を提供し、様々なデータ型を文字列として整形したり、文字列からデータを解析したりするために使用されます。
主な機能としては、以下のようなものがあります。
fmt.Print
,fmt.Println
,fmt.Printf
: 標準出力への出力fmt.Sprint
,fmt.Sprintln
,fmt.Sprintf
: 文字列への整形fmt.Fprint
,fmt.Fprintln
,fmt.Fprintf
: 指定されたio.Writer
への出力fmt.Scan
,fmt.Scanln
,fmt.Scanf
: 標準入力からの読み込みfmt.Sscan
,fmt.Sscanln
,fmt.Sscanf
: 文字列からの解析fmt.Fscan
,fmt.Fscanln
,fmt.Fscanf
: 指定されたio.Reader
からの読み込み
fmt
パッケージは、Goプログラムのデバッグ、ログ出力、ユーザーインターフェースの構築など、多岐にわたる場面で利用される基盤的なパッケージです。
技術的詳細
このコミットは、主にsrc/lib/fmt/format.go
とsrc/lib/fmt/print.go
の2つのファイルに影響を与えています。変更の核心は、Go言語のエクスポートルールに従って、識別子の可視性を調整することです。
src/lib/fmt/format.go
の変更点
このファイルは、fmt
パッケージの低レベルなフォーマット処理を担当するFmt
構造体とそのメソッドを定義しています。
-
定数の変更:
const NByte = 64;
がconst nByte = 64;
に変更されました。const NPows10 = 160;
がconst nPows10 = 160;
に変更されました。 これらの定数は、内部的なバッファサイズや数値計算に関連するものであり、外部に公開する必要がないため、小文字始まりに変更され、パッケージ内部でのみ利用可能になりました。
-
メソッドの変更:
-
func (f *Fmt) str() string
がfunc (f *Fmt) Str() string
に変更されました。 -
func (f *Fmt) put()
がfunc (f *Fmt) Put()
に変更されました。 -
func (f *Fmt) putnl()
がfunc (f *Fmt) Putnl()
に変更されました。 -
func (f *Fmt) wp(w, p int) *Fmt
がfunc (f *Fmt) Wp(w, p int) *Fmt
に変更されました。 -
func (f *Fmt) p(p int) *Fmt
がfunc (f *Fmt) P(p int) *Fmt
に変更されました。 -
func (f *Fmt) w(x int) *Fmt
がfunc (f *Fmt) W(x int) *Fmt
に変更されました。 これらのメソッドは、Fmt
オブジェクトの内部状態を操作したり、整形結果を取得したりするもので、以前は小文字始まりでしたが、このコミットで大文字始まりに変更され、エクスポートされるようになりました。これは、これらのメソッドがFmt
型の公開APIの一部として意図されていることを示唆しています。 -
func (f *Fmt) boolean(a bool) *Fmt
がfunc (f *Fmt) Fmt_boolean(a bool) *Fmt
に変更されました。 -
func (f *Fmt) d64(a int64) *Fmt
がfunc (f *Fmt) Fmt_d64(a int64) *Fmt
に変更されました。 -
同様に、
d32
,d
,ud64
,ud32
,ud
,x64
,x32
,x
,ux64
,ux32
,ux
,X64
,X32
,X
,uX64
,uX32
,uX
,o64
,o32
,o
,uo64
,uo32
,uo
,b64
,b32
,b
,c
,s
,sx
,sX
,q
,e64
,f64
,g64
,fb64
,e32
,f32
,g32
,fb32
といった、様々な型(整数、浮動小数点数、文字列など)のフォーマットを行うメソッドが、すべてFmt_
プレフィックスと大文字始まりの形式に変更されました。 これは、これらのメソッドがFmt
型の主要なフォーマット機能であり、公開APIとして提供されることを明確にするための変更です。Fmt_
プレフィックスは、これらのメソッドがFmt
オブジェクトのコンテキスト内で使用されることを強調しています。
-
-
関数の変更:
func FmtString(f *Fmt, s string) *Fmt
がfunc fmtString(f *Fmt, s string) *Fmt
に変更されました。 この関数は、内部的なヘルパー関数であり、外部に公開する必要がないため、小文字始まりに変更され、パッケージ内部でのみ利用可能になりました。
src/lib/fmt/print.go
の変更点
このファイルは、fmt
パッケージのより高レベルなプリント処理、特にPrintf
のような可変引数関数を扱うためのロジックを定義しています。
-
インターフェースの変更:
type Format interface {
がexport type Format interface {
に変更されました。type String interface {
がexport type String interface {
に変更されました。 これらのインターフェースは、カスタム型がfmt
パッケージのフォーマット機能と連携するための重要なメカニズムを提供します。以前は明示的にエクスポートされていませんでしたが、この変更により、これらのインターフェースが公開APIの一部として利用可能であることが明確になりました。
-
定数の変更:
const Runeself = 0x80
がconst runeSelf = 0x80
に変更されました。const AllocSize = 32
がconst allocSize = 32
に変更されました。 これらの定数は、内部的な文字処理やバッファ割り当てに関連するものであり、外部に公開する必要がないため、小文字始まりに変更され、パッケージ内部でのみ利用可能になりました。
-
構造体の変更:
type P struct {
がtype pp struct {
に変更されました。P
構造体は、fmt
パッケージの内部でプリント処理の状態を管理するために使用されるものであり、外部に公開する必要がないため、小文字始まりのpp
にリネームされ、パッケージ内部でのみ利用可能になりました。これに伴い、P
をレシーバーとするすべてのメソッドもpp
をレシーバーとするように変更されています。
-
メソッドの変更:
func Printer() *P
がfunc Printer() *pp
に変更されました。func (p *P) Width() ...
がfunc (p *pp) Width() ...
に変更されました。func (p *P) Precision() ...
がfunc (p *pp) Precision() ...
に変更されました。func (p *P) Flag(b int) bool
がfunc (p *pp) Flag(b int) bool
に変更されました。func (p *P) ensure(n int)
がfunc (p *pp) ensure(n int)
に変更されました。func (p *P) addstr(s string)
がfunc (p *pp) addstr(s string)
に変更されました。func (p *P) addbytes(b []byte, start, end int)
がfunc (p *pp) addbytes(b []byte, start, end int)
に変更されました。func (p *P) add(c int)
がfunc (p *pp) add(c int)
に変更されました。func (p *P) Write(b []byte) (ret int, err *os.Error)
がfunc (p *pp) Write(b []byte) (ret int, err *os.Error)
に変更されました。func (p *P) doprintf(format string, v reflect.StructValue)
がfunc (p *pp) doprintf(format string, v reflect.StructValue)
に変更されました。func (p *P) doprint(v reflect.StructValue, addspace, addnewline bool)
がfunc (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool)
に変更されました。func (p *P) printField(field reflect.Value) (was_string bool)
がfunc (p *pp) printField(field reflect.Value) (was_string bool)
に変更されました。 これらの変更は、P
構造体がpp
にリネームされたことに伴うもので、これらのメソッドもpp
の内部メソッドとして扱われることを示しています。
全体的な影響
このコミットは、fmt
パッケージの内部実装と公開APIの境界を明確に定義し直すものです。
- APIの整理: ユーザーが直接利用すべきメソッド(例:
Fmt_d
,Str
,Putnl
)はエクスポートされ、より直感的に利用できるようになります。 - 内部実装の隠蔽: 内部的なヘルパー関数や定数、構造体(例:
nByte
,allocSize
,pp
,fmtString
)はエクスポートされなくなり、パッケージの内部詳細が外部から見えなくなります。これにより、将来的な内部変更が外部のコードに影響を与えるリスクが低減されます。 - 一貫性の向上: Go言語の命名規則がパッケージ全体にわたってより厳密に適用され、コードベースの一貫性と可読性が向上します。
コアとなるコードの変更箇所
src/lib/fmt/format.go
--- a/src/lib/fmt/format.go
+++ b/src/lib/fmt/format.go
@@ -12,24 +12,22 @@ import (
Raw formatter. See print.go for a more palatable interface.
f := fmt.New();
- print f.d(1234).s("\n").str(); // create string, print it
- f.d(-1234).s("\n").put(); // print string
- f.ud(1<<63).putnl(); // print string with automatic newline
+ print f.Fmt_d(1234).Fmt_s("\n").Str(); // create string, print it
+ f.Fmt_d(-1234).Fmt_s("\n").put(); // print string
+ f.Fmt_ud(1<<63).Putnl(); // print string with automatic newline
*/
-// export Fmt, New;
-
-const NByte = 64;
-const NPows10 = 160;
+const nByte = 64;
+const nPows10 = 160;
var ldigits string = "0123456789abcdef" // var not const because we take its address
var udigits string = "0123456789ABCDEF"
-var pows10 [NPows10] float64;
+var pows10 [nPows10] float64;
func init() {
pows10[0] = 1.0e0;
pows10[1] = 1.0e1;
- for i:=2; i<NPows10; i++ {
+ for i:=2; i<nPows10; i++ {
m := i/2;
pows10[i] = pows10[m] * pows10[i-m];
}
@@ -76,7 +74,7 @@ export func New() *Fmt {
return f;
}
-func (f *Fmt) str() string {
+func (f *Fmt) Str() string {
s := f.buf;
f.clearbuf();
f.clearflags();
@@ -84,19 +82,19 @@ func (f *Fmt) str() string {
return s;
}
-func (f *Fmt) put() {
+func (f *Fmt) Put() {
print(f.buf);
f.clearbuf();
f.clearflags();
}
-func (f *Fmt) putnl() {
+func (f *Fmt) Putnl() {
print(f.buf, "\n");
f.clearbuf();
f.clearflags();
}
-func (f *Fmt) wp(w, p int) *Fmt {
+func (f *Fmt) Wp(w, p int) *Fmt {
f.wid_present = true;
f.wid = w;
f.prec_present = true;
@@ -104,13 +102,13 @@ func (f *Fmt) wp(w, p int) *Fmt {
return f;
}
-func (f *Fmt) p(p int) *Fmt {
+func (f *Fmt) P(p int) *Fmt {
f.prec_present = true;
f.prec = p;
return f;
}
-func (f *Fmt) w(x int) *Fmt {
+func (f *Fmt) W(x int) *Fmt {
f.wid_present = true;
f.wid = x;
return f;
@@ -132,8 +130,8 @@ func (f *Fmt) pad(s string) {
padchar = '0';
}
if w > 0 {
- if w > NByte {
- w = NByte;
+ if w > nByte {
+ w = nByte;
}
buf := make([]byte, w);
for i := 0; i < w; i++ {
@@ -154,7 +152,7 @@ func (f *Fmt) pad(s string) {
// never mind.) val is known to be unsigned. we could make things maybe
// marginally faster by splitting the 32-bit case out into a separate function
// but it's not worth the duplication, so val has 64 bits.\n-func putint(buf *[NByte]byte, i int, base, val uint64, digits *string) int {
+func putint(buf *[nByte]byte, i int, base, val uint64, digits *string) int {
for val >= base {
buf[i] = digits[val%base];
i--;
@@ -165,7 +163,7 @@ func putint(buf *[NByte]byte, i int, base, val uint64, digits *string) int {
}
// boolean
-func (f *Fmt) boolean(a bool) *Fmt {
+func (f *Fmt) Fmt_boolean(a bool) *Fmt {
if a {
f.pad("true");
} else {
@@ -177,7 +175,7 @@ func (f *Fmt) boolean(a bool) *Fmt {
// integer; interprets prec but not wid.
func (f *Fmt) integer(a int64, base uint, is_signed bool, digits *string) string {
-\tvar buf [NByte]byte;
+\tvar buf [nByte]byte;
negative := is_signed && a < 0;
if negative {
a = -a;
@@ -196,8 +194,8 @@ func (f *Fmt) integer(a int64, base uint, is_signed bool, digits *string) string
}
}
-\ti := putint(&buf, NByte-1, uint64(base), uint64(a), digits);
-\tfor i > 0 && prec > (NByte-1-i) {
+\ti := putint(&buf, nByte-1, uint64(base), uint64(a), digits);
+\tfor i > 0 && prec > (nByte-1-i) {\n \t\tbuf[i] = '0';
\t\ti--;
\t}
@@ -212,156 +210,156 @@ func (f *Fmt) integer(a int64, base uint, is_signed bool, digits *string) string
\tbuf[i] = ' ';
\ti--;
}
-\treturn string(buf)[i+1:NByte];
+\treturn string(buf)[i+1:nByte];
}
// decimal
-func (f *Fmt) d64(a int64) *Fmt {
+func (f *Fmt) Fmt_d64(a int64) *Fmt {
f.pad(f.integer(a, 10, true, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) d32(a int32) *Fmt {
-\treturn f.d64(int64(a));
+func (f *Fmt) Fmt_d32(a int32) *Fmt {
+\treturn f.Fmt_d64(int64(a));
}
-func (f *Fmt) d(a int) *Fmt {
-\treturn f.d64(int64(a));
+func (f *Fmt) Fmt_d(a int) *Fmt {
+\treturn f.Fmt_d64(int64(a));
}
-// unsigned decimal
-func (f *Fmt) ud64(a uint64) *Fmt {
+// unsigned Fmt_decimal
+func (f *Fmt) Fmt_ud64(a uint64) *Fmt {
f.pad(f.integer(int64(a), 10, false, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) ud32(a uint32) *Fmt {
-\treturn f.ud64(uint64(a));
+func (f *Fmt) Fmt_ud32(a uint32) *Fmt {
+\treturn f.Fmt_ud64(uint64(a));
}
-func (f *Fmt) ud(a uint) *Fmt {
-\treturn f.ud64(uint64(a));
+func (f *Fmt) Fmt_ud(a uint) *Fmt {
+\treturn f.Fmt_ud64(uint64(a));
}
// hexdecimal
-func (f *Fmt) x64(a int64) *Fmt {
+func (f *Fmt) Fmt_x64(a int64) *Fmt {
f.pad(f.integer(a, 16, true, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) x32(a int32) *Fmt {
-\treturn f.x64(int64(a));
+func (f *Fmt) Fmt_x32(a int32) *Fmt {
+\treturn f.Fmt_x64(int64(a));
}
-func (f *Fmt) x(a int) *Fmt {
-\treturn f.x64(int64(a));
+func (f *Fmt) Fmt_x(a int) *Fmt {
+\treturn f.Fmt_x64(int64(a));
}
// unsigned hexdecimal
-func (f *Fmt) ux64(a uint64) *Fmt {
+func (f *Fmt) Fmt_ux64(a uint64) *Fmt {
f.pad(f.integer(int64(a), 16, false, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) ux32(a uint32) *Fmt {
-\treturn f.ux64(uint64(a));
+func (f *Fmt) Fmt_ux32(a uint32) *Fmt {
+\treturn f.Fmt_ux64(uint64(a));
}
-func (f *Fmt) ux(a uint) *Fmt {
-\treturn f.ux64(uint64(a));
+func (f *Fmt) Fmt_ux(a uint) *Fmt {
+\treturn f.Fmt_ux64(uint64(a));
}
// HEXADECIMAL
-func (f *Fmt) X64(a int64) *Fmt {
+func (f *Fmt) Fmt_X64(a int64) *Fmt {
f.pad(f.integer(a, 16, true, &udigits));
f.clearflags();
return f;
}
-func (f *Fmt) X32(a int32) *Fmt {
-\treturn f.X64(int64(a));
+func (f *Fmt) Fmt_X32(a int32) *Fmt {
+\treturn f.Fmt_X64(int64(a));
}
-func (f *Fmt) X(a int) *Fmt {
-\treturn f.X64(int64(a));
+func (f *Fmt) Fmt_X(a int) *Fmt {
+\treturn f.Fmt_X64(int64(a));
}
// unsigned HEXADECIMAL
-func (f *Fmt) uX64(a uint64) *Fmt {
+func (f *Fmt) Fmt_uX64(a uint64) *Fmt {
f.pad(f.integer(int64(a), 16, false, &udigits));
f.clearflags();
return f;
}
-func (f *Fmt) uX32(a uint32) *Fmt {
-\treturn f.uX64(uint64(a));
+func (f *Fmt) Fmt_uX32(a uint32) *Fmt {
+\treturn f.Fmt_uX64(uint64(a));
}
-func (f *Fmt) uX(a uint) *Fmt {
-\treturn f.uX64(uint64(a));
+func (f *Fmt) Fmt_uX(a uint) *Fmt {
+\treturn f.Fmt_uX64(uint64(a));
}
// octal
-func (f *Fmt) o64(a int64) *Fmt {
+func (f *Fmt) Fmt_o64(a int64) *Fmt {
f.pad(f.integer(a, 8, true, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) o32(a int32) *Fmt {
-\treturn f.o64(int64(a));
+func (f *Fmt) Fmt_o32(a int32) *Fmt {
+\treturn f.Fmt_o64(int64(a));
}
-func (f *Fmt) o(a int) *Fmt {
-\treturn f.o64(int64(a));
+func (f *Fmt) Fmt_o(a int) *Fmt {
+\treturn f.Fmt_o64(int64(a));
}
// unsigned octal
-func (f *Fmt) uo64(a uint64) *Fmt {
+func (f *Fmt) Fmt_uo64(a uint64) *Fmt {
f.pad(f.integer(int64(a), 8, false, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) uo32(a uint32) *Fmt {
-\treturn f.uo64(uint64(a));
+func (f *Fmt) Fmt_uo32(a uint32) *Fmt {
+\treturn f.Fmt_uo64(uint64(a));
}
-func (f *Fmt) uo(a uint) *Fmt {
-\treturn f.uo64(uint64(a));
+func (f *Fmt) Fmt_uo(a uint) *Fmt {
+\treturn f.Fmt_uo64(uint64(a));
}
// unsigned binary
-func (f *Fmt) b64(a uint64) *Fmt {
+func (f *Fmt) Fmt_b64(a uint64) *Fmt {
f.pad(f.integer(int64(a), 2, false, &ldigits));
f.clearflags();
return f;
}
-func (f *Fmt) b32(a uint32) *Fmt {
-\treturn f.b64(uint64(a));
+func (f *Fmt) Fmt_b32(a uint32) *Fmt {
+\treturn f.Fmt_b64(uint64(a));
}
-func (f *Fmt) b(a uint) *Fmt {
-\treturn f.b64(uint64(a));
+func (f *Fmt) Fmt_b(a uint) *Fmt {
+\treturn f.Fmt_b64(uint64(a));
}
// character
-func (f *Fmt) c(a int) *Fmt {
+func (f *Fmt) Fmt_c(a int) *Fmt {
f.pad(string(a));
f.clearflags();
return f;
}
// string
-func (f *Fmt) s(s string) *Fmt {
+func (f *Fmt) Fmt_s(s string) *Fmt {
if f.prec_present {
if f.prec < len(s) {
s = s[0:f.prec];
@@ -373,7 +371,7 @@ func (f *Fmt) s(s string) *Fmt {
}
// hexadecimal string
-func (f *Fmt) sx(s string) *Fmt {
+func (f *Fmt) Fmt_sx(s string) *Fmt {
t := "";
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
@@ -388,7 +386,7 @@ func (f *Fmt) sx(s string) *Fmt {
return f;
}
-func (f *Fmt) sX(s string) *Fmt {
+func (f *Fmt) Fmt_sX(s string) *Fmt {
t := "";
for i := 0; i < len(s); i++ {
v := s[i];
@@ -401,7 +399,7 @@ func (f *Fmt) sX(s string) *Fmt {
}
// quoted string
-func (f *Fmt) q(s string) *Fmt {
+func (f *Fmt) Fmt_q(s string) *Fmt {
var quoted string;
if f.sharp && strconv.CanBackquote(s) {
quoted = "`"+s+"`";
@@ -422,73 +420,73 @@ func Prec(f *Fmt, def int) int {
return def;
}
-func FmtString(f *Fmt, s string) *Fmt {
+func fmtString(f *Fmt, s string) *Fmt {
f.pad(s);
f.clearflags();
return f;
}
// float64
-func (f *Fmt) e64(a float64) *Fmt {
-\treturn FmtString(f, strconv.ftoa64(a, 'e', Prec(f, 6)));
+func (f *Fmt) Fmt_e64(a float64) *Fmt {
+\treturn fmtString(f, strconv.ftoa64(a, 'e', Prec(f, 6)));
}
-func (f *Fmt) f64(a float64) *Fmt {
-\treturn FmtString(f, strconv.ftoa64(a, 'f', Prec(f, 6)));
+func (f *Fmt) Fmt_f64(a float64) *Fmt {
+\treturn fmtString(f, strconv.ftoa64(a, 'f', Prec(f, 6)));
}
-func (f *Fmt) g64(a float64) *Fmt {
-\treturn FmtString(f, strconv.ftoa64(a, 'g', Prec(f, -1)));
+func (f *Fmt) Fmt_g64(a float64) *Fmt {
+\treturn fmtString(f, strconv.ftoa64(a, 'g', Prec(f, -1)));
}
-func (f *Fmt) fb64(a float64) *Fmt {
-\treturn FmtString(f, strconv.ftoa64(a, 'b', 0));
+func (f *Fmt) Fmt_fb64(a float64) *Fmt {
+\treturn fmtString(f, strconv.ftoa64(a, 'b', 0));
}
// float32
// cannot defer to float64 versions
// because it will get rounding wrong in corner cases.
-func (f *Fmt) e32(a float32) *Fmt {
-\treturn FmtString(f, strconv.ftoa32(a, 'e', Prec(f, 6)));
+func (f *Fmt) Fmt_e32(a float32) *Fmt {
+\treturn fmtString(f, strconv.ftoa32(a, 'e', Prec(f, 6)));
}
-func (f *Fmt) f32(a float32) *Fmt {
-\treturn FmtString(f, strconv.ftoa32(a, 'f', Prec(f, 6)));
+func (f *Fmt) Fmt_f32(a float32) *Fmt {
+\treturn fmtString(f, strconv.ftoa32(a, 'f', Prec(f, 6)));
}
-func (f *Fmt) g32(a float32) *Fmt {
-\treturn FmtString(f, strconv.ftoa32(a, 'g', Prec(f, -1)));
+func (f *Fmt) Fmt_g32(a float32) *Fmt {
+\treturn fmtString(f, strconv.ftoa32(a, 'g', Prec(f, -1)));
}
-func (f *Fmt) fb32(a float32) *Fmt {
-\treturn FmtString(f, strconv.ftoa32(a, 'b', 0));
+func (f *Fmt) Fmt_fb32(a float32) *Fmt {
+\treturn fmtString(f, strconv.ftoa32(a, 'b', 0));
}
// float
func (x *Fmt) f(a float) *Fmt {
if strconv.floatsize == 32 {
-\t\treturn x.f32(float32(a))\n+\t\treturn x.Fmt_f32(float32(a))\n \t}
-\treturn x.f64(float64(a))\n+\treturn x.Fmt_f64(float64(a))\n }
func (x *Fmt) e(a float) *Fmt {
if strconv.floatsize == 32 {
-\t\treturn x.e32(float32(a))\n+\t\treturn x.Fmt_e32(float32(a))\n \t}
-\treturn x.e64(float64(a))\n+\treturn x.Fmt_e64(float64(a))\n }
func (x *Fmt) g(a float) *Fmt {
if strconv.floatsize == 32 {
-\t\treturn x.g32(float32(a))\n+\t\treturn x.Fmt_g32(float32(a))\n \t}
-\treturn x.g64(float64(a))\n+\treturn x.Fmt_g64(float64(a))\n }
func (x *Fmt) fb(a float) *Fmt {
if strconv.floatsize == 32 {
-\t\treturn x.fb32(float32(a))\n+\t\treturn x.Fmt_fb32(float32(a))\n \t}
-\treturn x.fb64(float64(a))\n+\treturn x.Fmt_fb64(float64(a))\n }
src/lib/fmt/print.go
--- a/src/lib/fmt/print.go
+++ b/src/lib/fmt/print.go
@@ -28,38 +28,38 @@ export type Formatter interface {
Flag(int) bool;
}
-type Format interface {
+export type Format interface {
Format(f Formatter, c int);
}
-type String interface {
+export type String interface {
String() string
}
-const Runeself = 0x80
-const AllocSize = 32
+const runeSelf = 0x80
+const allocSize = 32
-type P struct {
+type pp struct {
n int;
buf []byte;
fmt *Fmt;
}
-func Printer() *P {
-\tp := new(P);\n+\tp := new(pp);\n \tp.fmt = fmt.New();
\treturn p;
}
-func (p *P) Width() (wid int, ok bool) {
+func (p *pp) Width() (wid int, ok bool) {
\treturn p.fmt.wid, p.fmt.wid_present
}
-func (p *P) Precision() (prec int, ok bool) {
+func (p *pp) Precision() (prec int, ok bool) {
\treturn p.fmt.prec, p.fmt.prec_present
}
-func (p *P) Flag(b int) bool {
+func (p *pp) Flag(b int) bool {
\tswitch b {
\tcase '-':
\t\treturn p.fmt.minus;
@@ -75,11 +75,11 @@ func (p *P) Flag(b int) bool {
\treturn false
}
-func (p *P) ensure(n int) {
+func (p *pp) ensure(n int) {
\tif len(p.buf) < n {
-\t\tnewn := AllocSize + len(p.buf);\n+\t\tnewn := allocSize + len(p.buf);\n \t\tif newn < n {
-\t\t\tnewn = n + AllocSize\n+\t\t\tnewn = n + allocSize\n \t\t}\n \t\tb := make([]byte, newn);\
\t\tfor i := 0; i < p.n; i++ {
\t\t\tb[i] = p.buf[i];
\t\t}
@@ -88,7 +88,7 @@ func (p *P) ensure(n int) {
\t}\n }
-func (p *P) addstr(s string) {
+func (p *pp) addstr(s string) {
\tn := len(s);
\tp.ensure(p.n + n);
\tfor i := 0; i < n; i++ {
@@ -97,7 +97,7 @@ func (p *P) addstr(s string) {
\t}\n }
-func (p *P) addbytes(b []byte, start, end int) {
+func (p *pp) addbytes(b []byte, start, end int) {
\tp.ensure(p.n + end-start);
\tfor i := start; i < end; i++ {
\t\tp.buf[p.n] = b[i];
@@ -105,9 +105,9 @@ func (p *P) addbytes(b []byte, start, end int) {
\t}\n }
-func (p *P) add(c int) {
+func (p *pp) add(c int) {
\tp.ensure(p.n + 1);
-\tif c < Runeself {\n+\tif c < runeSelf {\n \t\tp.buf[p.n] = byte(c);
\t\tp.n++;
\t} else {
\t\tp.n += utf8.EncodeRune(p.buf[p.n:len(p.buf)], c);
@@ -115,13 +115,13 @@ func (p *P) add(c int) {
// Implement Write so we can call fprintf on a P, for
// recursive use in custom verbs.
-func (p *P) Write(b []byte) (ret int, err *os.Error) {
+func (p *pp) Write(b []byte) (ret int, err *os.Error) {
\tp.addbytes(b, 0, len(b));
\treturn len(b), nil;
}
-func (p *P) doprintf(format string, v reflect.StructValue);
-func (p *P) doprint(v reflect.StructValue, addspace, addnewline bool);
+func (p *pp) doprintf(format string, v reflect.StructValue);
+func (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool);
// These routines end in 'f' and take a format string.
@@ -329,34 +329,34 @@ func parsenum(s string, start, end int) (n int, got bool, newi int) {
\treturn num, isnum, start;
}
-func (p *P) printField(field reflect.Value) (was_string bool) {
+func (p *pp) printField(field reflect.Value) (was_string bool) {
\tinter := field.Interface();
\tif inter != nil {
\t\tif stringer, ok := inter.(String); ok {
\t\t\tp.addstr(stringer.String());
\t\t\treturn true;
\t\t}
\t\tif formatter, ok := inter.(Format); ok {
\t\t\tformatter.Format(p.fmt, 'v');
-\t\t\tp.addstr(p.fmt.str());
+\t\t\tp.addstr(p.fmt.Str());
\t\t\treturn false;
\t\t}
\t}
\ts := "";
\tswitch field.Kind() {
\tcase reflect.BoolKind:
-\t\ts = p.fmt.boolean(field.(reflect.BoolValue).Get()).str();
+\t\ts = p.fmt.Fmt_boolean(field.(reflect.BoolValue).Get()).Str();
\tcase reflect.IntKind, reflect.Int8Kind, reflect.Int16Kind, reflect.Int32Kind, reflect.Int64Kind:
\t\tv, signed, ok := getInt(field);
-\t\ts = p.fmt.d64(v).str();
+\t\ts = p.fmt.Fmt_d64(v).Str();
\tcase reflect.UintKind, reflect.Uint8Kind, reflect.Uint16Kind, reflect.Uint32Kind, reflect.Uint64Kind:
\t\tv, signed, ok := getInt(field);
-\t\ts = p.fmt.ud64(uint64(v)).str();
+\t\ts = p.fmt.Fmt_ud64(uint64(v)).Str();
\tcase reflect.UintptrKind:
\t\tv, signed, ok := getInt(field);
\t\tp.fmt.sharp = !p.fmt.sharp; // turn 0x on by default
-\t\ts = p.fmt.ux64(uint64(v)).str();
+\t\ts = p.fmt.Fmt_ux64(uint64(v)).Str();
\tcase reflect.Float32Kind:
\t\tv, ok := getFloat32(field);
-\t\ts = p.fmt.g32(v).str();
+\t\ts = p.fmt.Fmt_g32(v).Str();
\tcase reflect.Float64Kind, reflect.Float80Kind:
\t\tv, ok := getFloat64(field);
-\t\ts = p.fmt.g64(v).str();
+\t\ts = p.fmt.Fmt_g64(v).Str();
\tcase reflect.FloatKind:
\t\tif field.Type().Size()*8 == 32 {
\t\t\tv, ok := getFloat32(field);
-\t\t\ts = p.fmt.g32(v).str();
+\t\t\ts = p.fmt.Fmt_g32(v).Str();
\t\t} else {
\t\t\tv, ok := getFloat64(field);
-\t\t\ts = p.fmt.g64(v).str();
+\t\t\ts = p.fmt.Fmt_g64(v).Str();
\t\t}\n \tcase reflect.StringKind:
\t\tv, ok := getString(field);
-\t\ts = p.fmt.s(v).str();
+\t\ts = p.fmt.Fmt_s(v).Str();
\t\twas_string = true;
\tcase reflect.PtrKind:
\t\tif v, ok := getPtr(field); v == 0 {
@@ -385,7 +385,7 @@ func (p *P) printField(field reflect.Value) (was_string bool) {
\t\t\t\tp.addstr("]");
\t\t\t} else {
\t\t\t\tp.fmt.sharp = !p.fmt.sharp; // turn 0x on by default
-\t\t\t\ts = p.fmt.uX64(uint64(v)).str();
+\t\t\t\ts = p.fmt.Fmt_uX64(uint64(v)).Str();
\t\t\t}
\t\t}
\tcase reflect.ArrayKind:
@@ -433,7 +433,7 @@ func (p *P) printField(field reflect.Value) (was_string bool) {
\treturn was_string;
}
-func (p *P) doprintf(format string, v reflect.StructValue) {
+func (p *pp) doprintf(format string, v reflect.StructValue) {
\tp.ensure(len(format)); // a good starting size
\tend := len(format) - 1;
\tfieldnum := 0; // we process one field per non-trivial format
@@ -508,26 +508,26 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t\t\t// int
\t\t\tcase 'b':
\t\t\t\tif v, signed, ok := getInt(field); ok {
-\t\t\t\t\ts = p.fmt.b64(uint64(v)).str() // always unsigned
+\t\t\t\t\ts = p.fmt.Fmt_b64(uint64(v)).Str() // always unsigned
\t\t\t\t} else if v, ok := getFloat32(field); ok {
-\t\t\t\t\ts = p.fmt.fb32(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_fb32(v).Str()
\t\t\t\t} else if v, ok := getFloat64(field); ok {
-\t\t\t\t\ts = p.fmt.fb64(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_fb64(v).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}
\t\t\tcase 'c':
\t\t\t\tif v, signed, ok := getInt(field); ok {
-\t\t\t\t\ts = p.fmt.c(int(v)).str()
+\t\t\t\t\ts = p.fmt.Fmt_c(int(v)).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}
\t\t\tcase 'd':
\t\t\t\tif v, signed, ok := getInt(field); ok {
\t\t\t\t\tif signed {
-\t\t\t\t\t\ts = p.fmt.d64(v).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_d64(v).Str()
\t\t\t\t\t} else {
-\t\t\t\t\t\ts = p.fmt.ud64(uint64(v)).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_ud64(uint64(v)).Str()
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
@@ -535,9 +535,9 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t\t\tcase 'o':
\t\t\t\tif v, signed, ok := getInt(field); ok {
\t\t\t\t\tif signed {
-\t\t\t\t\t\ts = p.fmt.o64(v).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_o64(v).Str()
\t\t\t\t\t} else {
-\t\t\t\t\t\ts = p.fmt.uo64(uint64(v)).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_uo64(uint64(v)).Str()
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
@@ -545,24 +545,24 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t\t\tcase 'x':
\t\t\t\tif v, signed, ok := getInt(field); ok {
\t\t\t\t\tif signed {
-\t\t\t\t\t\ts = p.fmt.x64(v).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_x64(v).Str()
\t\t\t\t\t} else {
-\t\t\t\t\t\ts = p.fmt.ux64(uint64(v)).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_ux64(uint64(v)).Str()
\t\t\t\t\t}
\t\t\t\t} else if v, ok := getString(field); ok {
-\t\t\t\t\ts = p.fmt.sx(v).str();
+\t\t\t\t\ts = p.fmt.Fmt_sx(v).Str();
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}
\t\t\tcase 'X':
\t\t\t\tif v, signed, ok := getInt(field); ok {
\t\t\t\t\tif signed {
-\t\t\t\t\t\ts = p.fmt.X64(v).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_X64(v).Str()
\t\t\t\t\t} else {
-\t\t\t\t\t\ts = p.fmt.uX64(uint64(v)).str()
+\t\t\t\t\t\ts = p.fmt.Fmt_uX64(uint64(v)).Str()
\t\t\t\t\t}
\t\t\t\t} else if v, ok := getString(field); ok {
-\t\t\t\t\ts = p.fmt.sX(v).str();
+\t\t\t\t\ts = p.fmt.Fmt_sX(v).Str();
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}\n@@ -570,25 +570,25 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t\t\t// float
\t\t\tcase 'e':
\t\t\t\tif v, ok := getFloat32(field); ok {
-\t\t\t\t\ts = p.fmt.e32(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_e32(v).Str()
\t\t\t\t} else if v, ok := getFloat64(field); ok {
-\t\t\t\t\ts = p.fmt.e64(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_e64(v).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}\n \t\t\tcase 'f':
\t\t\t\tif v, ok := getFloat32(field); ok {
-\t\t\t\t\ts = p.fmt.f32(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_f32(v).Str()
\t\t\t\t} else if v, ok := getFloat64(field); ok {
-\t\t\t\t\ts = p.fmt.f64(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_f64(v).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}\n \t\t\tcase 'g':
\t\t\t\tif v, ok := getFloat32(field); ok {
-\t\t\t\t\ts = p.fmt.g32(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_g32(v).Str()
\t\t\t\t} else if v, ok := getFloat64(field); ok {
-\t\t\t\t\ts = p.fmt.g64(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_g64(v).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}\n@@ -596,13 +596,13 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t\t\t// string
\t\t\tcase 's':
\t\t\t\tif v, ok := getString(field); ok {
-\t\t\t\t\ts = p.fmt.s(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_s(v).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}\n \t\t\tcase 'q':
\t\t\t\tif v, ok := getString(field); ok {
-\t\t\t\t\ts = p.fmt.q(v).str()
+\t\t\t\t\ts = p.fmt.Fmt_q(v).Str()
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
\t\t\t\t}\n@@ -613,7 +613,7 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t\t\t\t\tif v == 0 {
\t\t\t\t\t\ts = "<nil>"
\t\t\t\t\t} else {
-\t\t\t\t\t\ts = "0x" + p.fmt.uX64(uint64(v)).str()
+\t\t\t\t\t\ts = "0x" + p.fmt.Fmt_uX64(uint64(v)).Str()
\t\t\t\t\t}
\t\t\t\t} else {
\t\t\t\t\tgoto badtype
@@ -645,7 +645,7 @@ func (p *P) doprintf(format string, v reflect.StructValue) {
\t}\n }
-func (p *P) doprint(v reflect.StructValue, addspace, addnewline bool) {
+func (p *pp) doprint(v reflect.StructValue, addspace, addnewline bool) {
\tprev_string := false;
\tfor fieldnum := 0; fieldnum < v.Len(); fieldnum++ {
\t\t// always add spaces if we're doing println
コアとなるコードの解説
このコミットの主要な変更は、Go言語の命名規則(大文字始まりはエクスポート、小文字始まりは非エクスポート)をfmt
パッケージ全体に適用し、APIの明確化と内部実装のカプセル化を強化することです。
format.go
における変更の意図
- 定数の非エクスポート化:
NByte
やNPows10
といった定数がnByte
やnPows10
にリネームされたのは、これらがfmt
パッケージの内部的なバッファ管理や数値計算にのみ使用され、外部のユーザーが直接参照したり変更したりする必要がないためです。これにより、内部実装の詳細が隠蔽され、パッケージの保守性が向上します。 Fmt
メソッドのエクスポート化とプレフィックス付与:str()
,put()
,putnl()
,wp()
,p()
,w()
といったメソッドが、それぞれStr()
,Put()
,Putnl()
,Wp()
,P()
,W()
にリネームされ、エクスポートされるようになりました。これらのメソッドは、Fmt
オブジェクトの基本的な操作(文字列の取得、出力、幅や精度の設定など)を提供するため、公開APIとして適切であると判断されたと考えられます。boolean()
,d64()
,x64()
などの様々なフォーマットメソッドが、Fmt_boolean()
,Fmt_d64()
,Fmt_x64()
のようにFmt_
プレフィックスと大文字始まりの形式に変更されました。このFmt_
プレフィックスは、これらのメソッドがFmt
型のインスタンスに紐づくフォーマット機能であることを明確に示し、APIの意図をより分かりやすくしています。これは、Go言語の初期段階におけるAPI設計の試行錯誤の一環であり、特定の型に特化したメソッドであることを強調する目的があったと考えられます。
- ヘルパー関数の非エクスポート化:
FmtString()
がfmtString()
にリネームされたのは、この関数がFmt
パッケージ内部でのみ使用されるヘルパー関数であり、外部に公開する必要がないためです。
print.go
における変更の意図
- インターフェースのエクスポート化:
Format
とString
インターフェースが明示的にexport type
として宣言されました。これらのインターフェースは、ユーザーが独自の型をfmt
パッケージのフォーマット機能と連携させるための重要な拡張ポイントです。例えば、String()
メソッドを実装することで、fmt.Print
系の関数でその型を文字列として出力できるようになります。これらのインターフェースをエクスポートすることで、fmt
パッケージの柔軟性と拡張性が向上します。 - 定数の非エクスポート化:
Runeself
やAllocSize
といった定数がruneSelf
やallocSize
にリネームされたのは、これらが内部的な文字エンコーディングやバッファ割り当ての最適化に使用されるものであり、外部に公開する必要がないためです。 - 構造体の非エクスポート化:
P
構造体がpp
にリネームされ、非エクスポート化されました。P
構造体は、fmt
パッケージの内部でプリント処理の状態を管理するためのものであり、ユーザーが直接操作することを意図していません。これを非エクスポート化することで、内部実装の詳細が隠蔽され、パッケージのAPIがよりクリーンになります。これに伴い、P
をレシーバーとするすべてのメソッドもpp
をレシーバーとするように変更されています。
これらの変更は、Go言語の設計原則である「シンプルさ」と「明確さ」をfmt
パッケージに適用し、公開APIと内部実装の境界を明確にすることで、パッケージの使いやすさ、保守性、そして将来的な進化の柔軟性を高めることを目的としています。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
fmt
パッケージのドキュメント: https://pkg.go.dev/fmt- Go言語の命名規則に関する公式ブログ記事("Effective Go"より): https://go.dev/doc/effective_go#names
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- Go言語のコミット履歴: https://github.com/golang/go/commits/master
- Go言語の初期開発に関する情報(Go Wikiなど): https://go.dev/wiki/
- Go言語のEffective Go: https://go.dev/doc/effective_go
- Go言語の
reflect
パッケージのドキュメント (コミット内容にreflect.StructValue
などの利用が見られるため): https://pkg.go.dev/reflect - Go言語の
strconv
パッケージのドキュメント (コミット内容にstrconv.ftoa64
などの利用が見られるため): https://pkg.go.dev/strconv