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

[インデックス 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の命名規則の厳密な適用と、それに伴うコードベース全体のリファクタリングに集約されます。

  1. 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 は小文字で始まっており、パッケージローカルであることを示唆していました。しかし、fmtreflectパッケージから参照されていることから、これは実際には公開されるべき情報であったと考えられます。
    • src/lib/strconv/ftoa.go では、func FloatSize() intfunc floatsize() int にリネームされ、その戻り値を export var FloatSize = floatsize() という形で新しいエクスポートされた変数 FloatSize に代入しています。これは、floatsize() 関数自体はパッケージ内部のヘルパー関数であり、その結果(Goのfloat型が32ビットか64ビットかを示す情報)のみが FloatSize というエクスポートされた変数として公開されるべきであるという意図を明確にしています。
  2. 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 のような真に公開されるべき定数が明示的にエクスポートされています。
  3. reflect パッケージ内の基底構造体のリネーム:

    • src/lib/reflect/type.gosrc/lib/reflect/value.go で、Common という構造体がそれぞれ commonTypecommonValue にリネームされています。
    • Common は、リフレクションにおける型や値の共通の基底構造体として使用されていました。しかし、その名前が大文字で始まるため、外部にエクスポートされているかのように見えました。実際には、これはreflectパッケージの内部実装の詳細であり、外部から直接アクセスされるべきではありません。
    • このリネームにより、commonTypecommonValue は小文字で始まるため、パッケージローカルであることが明確になり、APIの境界がより厳密に定義されました。
  4. テストコードのリネーム:

    • 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 から AtofTesttests から atoftests)。
    • これは、Goの命名規則に直接関連するものではありませんが、コードベース全体での一貫性を保つためのクリーンアップの一環です。

これらの変更は、Go言語の設計原則である「明示的な可視性」をコードベース全体に徹底させるためのものであり、GoのAPI設計の初期段階における重要なステップでした。

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

このコミットにおけるコアとなるコードの変更は、主に以下のパターンに分類されます。

  1. エクスポートされるべき識別子の小文字から大文字への変更:

    • 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()
      
  2. パッケージローカルにすべき識別子の大文字から小文字への変更:

    • 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} }
       }
      
  3. 新しいエクスポートされた定数ファイルの追加:

    • 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;
      )
      

コアとなるコードの解説

  1. strconv.floatsize から strconv.FloatSize への変更:

    • この変更は、strconvパッケージが提供する浮動小数点数の内部表現サイズ(32ビットか64ビットか)を示す情報が、パッケージ外部から参照されるべき公開APIの一部であることを明確にしています。
    • src/lib/strconv/ftoa.go では、FloatSize() という関数が floatsize() にリネームされ、その結果が FloatSize というエクスポートされた変数に代入されるようになりました。これは、floatsize() 関数自体は内部的な実装の詳細であり、その計算結果のみが公開されるべきであるというGoの設計思想を反映しています。これにより、strconv.FloatSize を参照する他のパッケージ(fmtreflectなど)は、Goの浮動小数点数のサイズに関する情報を正しく取得できるようになります。
  2. math パッケージ内の定数と関数のリネーム:

    • atan.go, log.go, sin.go, sinh.go などで行われた定数やヘルパー関数のリネームは、これらの識別子が数学関数の内部計算に使用されるものであり、パッケージの外部インターフェースには含まれないことを明確にしています。
    • 例えば、atan.gop0, q0 などの多項式近似の係数や、Xatan, Satan といった内部ヘルパー関数は、Atan 関数を実装するための内部的な詳細です。これらを小文字で始まる名前に変更することで、Goの可視性ルールに従い、これらの識別子がパッケージローカルであることを明示しています。
    • これにより、mathパッケージのユーザーは、公開された Atan, Log, Sin, Cos, Sinh などの関数のみを安心して利用でき、内部実装の変更に影響されることなく、安定したAPIを利用できます。
    • 新しく追加された src/lib/math/const.go は、Sqrt2 のような普遍的な数学定数を明示的にエクスポートするために使用されます。これにより、Goのユーザーは math.Sqrt2 としてこの定数にアクセスできるようになります。
  3. reflect パッケージ内の基底構造体のリネーム:

    • reflectパッケージの Common 構造体が commonType および commonValue にリネームされたことは、リフレクションの内部実装における基底型が、パッケージ外部に公開されるべきではないことを示しています。
    • reflectパッケージは、Goの型システムを動的に操作するための強力なツールですが、その内部構造は複雑であり、通常は直接操作されることを意図していません。Common のような基底構造体が大文字で始まっていると、誤って外部から参照されたり、依存関係が生まれたりする可能性があります。
    • このリネームにより、commonTypecommonValue はパッケージローカルとなり、reflectパッケージの内部実装がより適切にカプセル化され、APIの安定性と保守性が向上します。

これらの変更は、Go言語の初期段階において、その設計原則、特に「シンプルさ」と「明瞭なAPI境界」をコードベース全体に浸透させるための重要なステップでした。これにより、Goのコードはより読みやすく、理解しやすく、そして長期的に保守しやすいものとなりました。

関連リンク

参考にした情報源リンク