[インデックス 1485] ファイルの概要
このコミットは、Go言語の初期開発段階における重要なリファクタリングであり、Goのパッケージにおける識別子の可視性(エクスポートされるか、パッケージローカルであるか)に関する新しいデフォルトルールにコードベースを適合させることを目的としています。具体的には、公開APIとして意図された識別子は大文字で始まり、パッケージ内部でのみ使用される識別子は小文字で始まるというGoの命名規則を厳密に適用するために、多数の変数、定数、関数、および構造体の名前が変更されています。これにより、コードの意図が明確になり、APIの境界がより厳密に定義されます。
コミット
commit b54133d20039a20bfba25574b5f87e4a370a032e
Author: Russ Cox <rsc@golang.org>
Date: Thu Jan 15 16:16:42 2009 -0800
make safe for new package local defaults
R=r
DELTA=462 (9 added, 33 deleted, 420 changed)
OCL=22879
CL=22885
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b54133d20039a20bfba25574b5f87e4a370a032e
元コミット内容
make safe for new package local defaults
変更の背景
このコミットが行われた2009年1月は、Go言語がまだ活発に開発され、その設計原則が固まりつつあった時期です。Go言語の設計思想の一つに「シンプルさと明瞭さ」があります。その一環として、識別子の命名規則を通じて、その識別子がパッケージ外部からアクセス可能(エクスポートされる)か、それともパッケージ内部でのみ使用される(エクスポートされない、またはパッケージローカル)かを明確にするというルールが導入されました。
具体的には、Goでは識別子(変数、関数、型、定数など)の最初の文字が大文字である場合、その識別子はパッケージ外部にエクスポートされ、他のパッケージから参照可能になります。一方、最初の文字が小文字である場合、その識別子はパッケージローカルとなり、定義されたパッケージ内でのみアクセス可能です。
このコミット以前は、この規則がコードベース全体で一貫して適用されていなかった可能性があります。例えば、内部的なヘルパー関数や定数が誤って大文字で始まっていたり、逆に外部に公開されるべき識別子が小文字で始まっていたりするケースがあったと考えられます。
「new package local defaults(新しいパッケージローカルのデフォルト)」というコミットメッセージは、この可視性ルールがGo言語の標準的な振る舞いとして確立され、それに合わせて既存のコードベースを修正する必要があったことを示唆しています。この変更により、Goのコードはより予測可能で、保守しやすくなり、APIの意図が明確になります。
前提知識の解説
Go言語のパッケージと可視性
Go言語は、コードをpackage
という単位で整理します。各パッケージは、関連する機能の集合体であり、独自のスコープを持ちます。Goにおける識別子の可視性(Visibility)は、このパッケージシステムと密接に関連しています。
- エクスポートされた識別子 (Exported Identifiers): 識別子の最初の文字が大文字である場合(例:
MyVariable
,CalculateSum
,MyStruct
)、その識別子はパッケージ外部にエクスポートされます。これにより、他のパッケージからその識別子を参照し、利用することが可能になります。これらは、そのパッケージの公開APIの一部と見なされます。 - エクスポートされない識別子 (Unexported Identifiers): 識別子の最初の文字が小文字である場合(例:
myVariable
,calculateSum
,myStruct
)、その識別子はパッケージローカルであり、定義されたパッケージ内でのみアクセス可能です。他のパッケージからは直接参照することはできません。これらは、パッケージの内部実装の詳細と見なされます。
このシンプルなルールは、Goのコードベースを整理し、モジュール性を高める上で非常に強力です。開発者は、識別子の名前を見るだけで、それが公開APIの一部なのか、それとも内部実装の詳細なのかをすぐに判断できます。
reflect
パッケージ
reflect
パッケージは、Goプログラムが実行時に自身の構造を検査(リフレクション)することを可能にします。これにより、変数の型、値、構造体のフィールド、メソッドなどを動的に調べたり、操作したりすることができます。これは、ジェネリックなデータ処理、シリアライゼーション/デシリアライゼーション、テストフレームワークなどで利用されます。
strconv
パッケージ
strconv
パッケージは、基本的なデータ型(数値、真偽値、文字列など)と文字列との間の変換機能を提供します。例えば、文字列を整数に変換したり(Atoi
)、浮動小数点数を文字列に変換したり(FormatFloat
)する機能が含まれます。
math
パッケージ
math
パッケージは、Go言語の標準ライブラリの一部であり、一般的な数学関数(三角関数、対数関数、平方根など)や数学定数を提供します。
技術的詳細
このコミットの技術的な詳細は、Goの命名規則の厳密な適用と、それに伴うコードベース全体のリファクタリングに集約されます。
-
strconv.floatsize
からstrconv.FloatSize
への変更:src/lib/fmt/format.go
,src/lib/reflect/tostring.go
,src/lib/strconv/atof.go
,src/lib/strconv/ftoa.go
の各ファイルで、strconv.floatsize
という識別子がstrconv.FloatSize
に変更されています。- 元の
floatsize
は小文字で始まっており、パッケージローカルであることを示唆していました。しかし、fmt
やreflect
パッケージから参照されていることから、これは実際には公開されるべき情報であったと考えられます。 src/lib/strconv/ftoa.go
では、func FloatSize() int
がfunc floatsize() int
にリネームされ、その戻り値をexport var FloatSize = floatsize()
という形で新しいエクスポートされた変数FloatSize
に代入しています。これは、floatsize()
関数自体はパッケージ内部のヘルパー関数であり、その結果(Goのfloat
型が32ビットか64ビットかを示す情報)のみがFloatSize
というエクスポートされた変数として公開されるべきであるという意図を明確にしています。
-
math
パッケージ内の定数と関数のリネーム:src/lib/math/atan.go
,src/lib/math/log.go
,src/lib/math/sin.go
,src/lib/math/sinh.go
の各ファイルで、多くの定数(例:p0
,q0
,Ln2Hi
,Lg1
,piu2
)や内部ヘルパー関数(例:Xatan
,Satan
,Sinus
)が、小文字で始まる名前に変更されています(例:ap0
,aq0
,ln2Hi
,lg1
,spiu2
,xatan
,satan
,sinus
)。- これは、これらの識別子が数学関数の内部計算に使用される定数やヘルパー関数であり、パッケージ外部に公開されるべきではないというGoの命名規則に合わせた変更です。これにより、
math
パッケージの公開APIがより明確になり、内部実装の詳細が隠蔽されます。 src/lib/math/const.go
という新しいファイルが追加され、export const ( Sqrt2 = ... )
のように、Sqrt2
のような真に公開されるべき定数が明示的にエクスポートされています。
-
reflect
パッケージ内の基底構造体のリネーム:src/lib/reflect/type.go
とsrc/lib/reflect/value.go
で、Common
という構造体がそれぞれcommonType
とcommonValue
にリネームされています。Common
は、リフレクションにおける型や値の共通の基底構造体として使用されていました。しかし、その名前が大文字で始まるため、外部にエクスポートされているかのように見えました。実際には、これはreflect
パッケージの内部実装の詳細であり、外部から直接アクセスされるべきではありません。- このリネームにより、
commonType
とcommonValue
は小文字で始まるため、パッケージローカルであることが明確になり、APIの境界がより厳密に定義されました。
-
テストコードのリネーム:
src/lib/strconv/atof_test.go
,src/lib/strconv/atoi_test.go
,src/lib/strconv/ftoa_test.go
,src/lib/strconv/itoa_test.go
の各ファイルで、テスト用の構造体や変数の名前が変更されています(例:Test
からAtofTest
、tests
からatoftests
)。- これは、Goの命名規則に直接関連するものではありませんが、コードベース全体での一貫性を保つためのクリーンアップの一環です。
これらの変更は、Go言語の設計原則である「明示的な可視性」をコードベース全体に徹底させるためのものであり、GoのAPI設計の初期段階における重要なステップでした。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、主に以下のパターンに分類されます。
-
エクスポートされるべき識別子の小文字から大文字への変更:
src/lib/fmt/format.go
--- a/src/lib/fmt/format.go +++ b/src/lib/fmt/format.go @@ -464,28 +464,28 @@ func (f *Fmt) Fmt_fb32(a float32) *Fmt { // float func (x *Fmt) f(a float) *Fmt { - if strconv.floatsize == 32 { + if strconv.FloatSize == 32 { return x.Fmt_f32(float32(a)) } return x.Fmt_f64(float64(a)) }
src/lib/strconv/ftoa.go
--- a/src/lib/strconv/ftoa.go +++ b/src/lib/strconv/ftoa.go @@ -28,7 +28,7 @@ func GenericFtoa(bits uint64, fmt byte, prec int, flt *FloatInfo) string func Max(a, b int) int func RoundShortest(d *Decimal, mant uint64, exp int, flt *FloatInfo) -func FloatSize() int { +func floatsize() int { // Figure out whether float is float32 or float64. // 1e-35 is representable in both, but 1e-70 // is too small for a float32. @@ -38,7 +38,7 @@ func FloatSize() int { } return 64; } -export var floatsize = FloatSize() +export var FloatSize = floatsize()
-
パッケージローカルにすべき識別子の大文字から小文字への変更:
src/lib/math/atan.go
--- a/src/lib/math/atan.go +++ b/src/lib/math/atan.go @@ -15,30 +15,30 @@ package math const ( - p4 = .161536412982230228262e2; - p3 = .26842548195503973794141e3; - p2 = .11530293515404850115428136e4; - p1 = .178040631643319697105464587e4; - p0 = .89678597403663861959987488e3; - q4 = .5895697050844462222791e2; - q3 = .536265374031215315104235e3; - q2 = .16667838148816337184521798e4; - q1 = .207933497444540981287275926e4; - q0 = .89678597403663861962481162e3; - pio2 = .15707963267948966192313216e1; - pio4 = .7853981633974483096156608e0; - sq2p1 = .2414213562373095048802e1; // sqrt(2)+1 - sq2m1 = .414213562373095048802e0; // sqrt(2)-1 + ap4 = .161536412982230228262e2; + ap3 = .26842548195503973794141e3; + ap2 = .11530293515404850115428136e4; + ap1 = .178040631643319697105464587e4; + ap0 = .89678597403663861959987488e3; + aq4 = .5895697050844462222791e2; + aq3 = .536265374031215315104235e3; + aq2 = .16667838148816337184521798e4; + aq1 = .207933497444540981287275926e4; + aq0 = .89678597403663861962481162e3; + apio2 = .15707963267948966192313216e1; + apio4 = .7853981633974483096156608e0; + asq2p1 = .2414213562373095048802e1; // sqrt(2)+1 + asq2m1 = .414213562373095048802e0; // sqrt(2)-1 ) /* * xatan evaluates a series valid in the * range [-0.414...,+0.414...]. (tan(pi/8)) */ -func Xatan(arg float64) float64 { +func xatan(arg float64) float64 { argsq := arg*arg; - value := ((((p4*argsq + p3)*argsq + p2)*argsq + p1)*argsq + p0); - value = value/(((((argsq + q4)*argsq + q3)*argsq + q2)*argsq + q1)*argsq + q0); + value := ((((ap4*argsq + ap3)*argsq + ap2)*argsq + ap1)*argsq + ap0); + value = value/(((((argsq + aq4)*argsq + aq3)*argsq + aq2)*argsq + aq1)*argsq + aq0); return value*arg; }
src/lib/reflect/type.go
--- a/src/lib/reflect/type.go +++ b/src/lib/reflect/type.go @@ -59,22 +59,22 @@ export type Type interface { } // Fields and methods common to all types -type Common struct { +type commonType struct { kind int; str string; name string; size int; } -func (c *Common) Kind() int { +func (c *commonType) Kind() int { return c.kind } -func (c *Common) Name() string { +func (c *commonType) Name() string { return c.name } -func (c *Common) String() string { +func (c *commonType) String() string { // If there is a name, show that instead of its expansion. // This is important for reflection: a named type // might have methods that the unnamed type does not. @@ -84,18 +84,18 @@ func (c *Common) String() string { return c.str } -func (c *Common) Size() int { +func (c *commonType) Size() int { return c.size } // -- Basic type BasicType struct { - Common + commonType } func NewBasicType(name string, kind int, size int) Type { - return &BasicType{ Common{kind, name, name, size} } + return &BasicType{ commonType{kind, name, name, size} } }
-
新しいエクスポートされた定数ファイルの追加:
src/lib/math/const.go
(新規ファイル)// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package math export const ( Sqrt2 = 1.41421356237309504880168872420969808; )
コアとなるコードの解説
-
strconv.floatsize
からstrconv.FloatSize
への変更:- この変更は、
strconv
パッケージが提供する浮動小数点数の内部表現サイズ(32ビットか64ビットか)を示す情報が、パッケージ外部から参照されるべき公開APIの一部であることを明確にしています。 src/lib/strconv/ftoa.go
では、FloatSize()
という関数がfloatsize()
にリネームされ、その結果がFloatSize
というエクスポートされた変数に代入されるようになりました。これは、floatsize()
関数自体は内部的な実装の詳細であり、その計算結果のみが公開されるべきであるというGoの設計思想を反映しています。これにより、strconv.FloatSize
を参照する他のパッケージ(fmt
やreflect
など)は、Goの浮動小数点数のサイズに関する情報を正しく取得できるようになります。
- この変更は、
-
math
パッケージ内の定数と関数のリネーム:atan.go
,log.go
,sin.go
,sinh.go
などで行われた定数やヘルパー関数のリネームは、これらの識別子が数学関数の内部計算に使用されるものであり、パッケージの外部インターフェースには含まれないことを明確にしています。- 例えば、
atan.go
のp0
,q0
などの多項式近似の係数や、Xatan
,Satan
といった内部ヘルパー関数は、Atan
関数を実装するための内部的な詳細です。これらを小文字で始まる名前に変更することで、Goの可視性ルールに従い、これらの識別子がパッケージローカルであることを明示しています。 - これにより、
math
パッケージのユーザーは、公開されたAtan
,Log
,Sin
,Cos
,Sinh
などの関数のみを安心して利用でき、内部実装の変更に影響されることなく、安定したAPIを利用できます。 - 新しく追加された
src/lib/math/const.go
は、Sqrt2
のような普遍的な数学定数を明示的にエクスポートするために使用されます。これにより、Goのユーザーはmath.Sqrt2
としてこの定数にアクセスできるようになります。
-
reflect
パッケージ内の基底構造体のリネーム:reflect
パッケージのCommon
構造体がcommonType
およびcommonValue
にリネームされたことは、リフレクションの内部実装における基底型が、パッケージ外部に公開されるべきではないことを示しています。reflect
パッケージは、Goの型システムを動的に操作するための強力なツールですが、その内部構造は複雑であり、通常は直接操作されることを意図していません。Common
のような基底構造体が大文字で始まっていると、誤って外部から参照されたり、依存関係が生まれたりする可能性があります。- このリネームにより、
commonType
とcommonValue
はパッケージローカルとなり、reflect
パッケージの内部実装がより適切にカプセル化され、APIの安定性と保守性が向上します。
これらの変更は、Go言語の初期段階において、その設計原則、特に「シンプルさ」と「明瞭なAPI境界」をコードベース全体に浸透させるための重要なステップでした。これにより、Goのコードはより読みやすく、理解しやすく、そして長期的に保守しやすいものとなりました。
関連リンク
参考にした情報源リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Effective Go: https://go.dev/doc/effective_go
- Go言語のソースコード (GitHub): https://github.com/golang/go
- Go言語のメーリングリストアーカイブ (golang-nuts): https://groups.google.com/g/golang-nuts
- Go言語の命名規則に関する一般的な情報源 (例: Goのブログ記事やチュートリアル)