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

[インデックス 1197] ファイルの概要

このコミットは、Go言語の標準ライブラリmathパッケージにおける大幅なリファクタリングとテストフレームワークの移行を目的としています。具体的には、mathパッケージ内の関数名をGoの慣習に従ってエクスポート可能な形式(先頭大文字)に変更し、変数宣言をより簡潔な形式(:=演算子)に統一しています。また、カスタムのテストフレームワークからGo標準のtestingパッケージへの移行が行われ、テストコードの構造と記述方法が改善されています。

コミット

commit 88daac7862531c606345787f2adff6cf845808d7
Author: Russ Cox <rsc@golang.org>
Date:   Wed Nov 19 16:14:31 2008 -0800

    gotestify & gostylify math.
    
    R=r
    DELTA=682  (275 added, 301 deleted, 106 changed)
    OCL=19638
    CL=19642

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/88daac7862531c606345787f2adff6cf845808d7

元コミット内容

gotestify & gostylify math.

このコミットメッセージは、「mathパッケージをテスト可能にし、Goのスタイルに合わせる」という意図を簡潔に示しています。gotestifyはテストの改善、gostylifyはGoのコーディング規約への準拠を意味すると考えられます。

変更の背景

このコミットが行われた2008年11月は、Go言語がまだ一般に公開される前の開発初期段階にあたります。Go言語は、その設計思想として「シンプルさ」「効率性」「並行処理」を重視しており、その一環としてコードの可読性や保守性を高めるための明確なコーディング規約(Go ProverbsやEffective Goとして後にまとめられるもの)が形成されつつありました。

変更の背景には、以下の点が挙げられます。

  1. Go言語の慣習の確立: Go言語では、関数や変数、型の名前の先頭文字が大文字か小文字かによって、その可視性(エクスポートされるか否か)が決定されます。このコミット以前は、mathパッケージ内の多くの関数が小文字で始まっており、パッケージ外から直接利用できない状態でした。標準ライブラリとして提供されるべき数学関数群が、外部から利用できるようにエクスポートされる必要がありました。
  2. 標準テストフレームワークの採用: Go言語には、testingパッケージという組み込みのテストフレームワークが存在します。このコミット以前は、カスタムのテストユーティリティ(test/mathtest.goに見られるck関数など)が使用されていましたが、Go言語の成熟に伴い、標準のtestingパッケージに移行することで、テストの記述、実行、レポート生成をより標準的かつ効率的に行うことが可能になります。これにより、開発者は一貫した方法でテストを記述し、Goのエコシステムが提供するツール(go testコマンドなど)を最大限に活用できるようになります。
  3. コードの簡潔化と可読性向上: varキーワードを用いた冗長な変数宣言を、型推論を伴う短縮変数宣言:=に置き換えることで、コードの記述量を減らし、可読性を向上させる狙いがあります。これはGo言語の設計哲学である「簡潔さ」に合致する変更です。
  4. パッケージインポートの整理: import math "math"のような冗長なパッケージエイリアスを削除し、import "math"とすることで、コードの簡潔さを追求しています。

これらの変更は、Go言語が初期段階から、その設計思想に基づいた堅牢で一貫性のある標準ライブラリを構築しようとしていたことを示しています。

前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念を理解しておく必要があります。

  1. Go言語の可視性ルール(Exported Names): Go言語では、パッケージ内の識別子(変数、関数、型、メソッドなど)の可視性は、その名前の先頭文字が大文字か小文字かによって決まります。

    • 大文字で始まる識別子: パッケージ外からアクセス可能です(エクスポートされます)。これは他の言語におけるpublicに相当します。
    • 小文字で始まる識別子: その識別子が定義されているパッケージ内からのみアクセス可能です(エクスポートされません)。これは他の言語におけるprivateinternalに相当します。 このコミットでは、asinAsinに、atanAtanにといった形で、多くの数学関数が小文字から大文字に名前が変更されており、これによりこれらの関数がmathパッケージの外部から利用可能になっています。
  2. 短縮変数宣言 (:=): Go言語では、変数を宣言し、同時に初期値を代入する際に、varキーワードと型名を省略して:=演算子を使用することができます。これは「短縮変数宣言」と呼ばれ、関数のローカル変数でよく使われます。 例: var x float64 = 10.0x := 10.0 と書くことができます。 このコミットでは、多くの場所でvar temp, x float64;のような宣言がtemp, x := ...のような形式に変更されています。

  3. Go言語のtestingパッケージ: Go言語には、ユニットテストやベンチマークテストを記述するための標準パッケージtestingが用意されています。

    • テスト関数はTestで始まり、*testing.T型の引数を一つ取ります(例: func TestFunctionName(t *testing.T))。
    • テストの失敗を報告するには、t.Errort.Errorfなどのメソッドを使用します。
    • テストファイルは、テスト対象のソースファイルと同じディレクトリに配置され、ファイル名の末尾が_test.goである必要があります。 このコミットでは、カスタムのテストロジックから、この標準的なtestingパッケージを利用したテストコードへの移行が行われています。
  4. Go言語の慣用句(Idiomatic Go): Go言語には、コードの可読性、保守性、効率性を高めるための推奨されるコーディングスタイルやパターンが存在します。これらは「Goの慣用句」と呼ばれ、Effective Goなどの公式ドキュメントで詳しく説明されています。関数名のエクスポートルールや短縮変数宣言の活用も、この慣用句の一部です。

技術的詳細

このコミットは、Go言語のsrc/lib/mathディレクトリ内の複数のファイルにわたる広範な変更を含んでいます。主な技術的変更点は以下の通りです。

  1. 関数名の変更とエクスポート: asin.go, atan.go, atan2.go, exp.go, fabs.go, floor.go, fmod.go, hypot.go, log.go, pow.go, pow10.go, sin.go, sinh.go, sqrt.go, tan.go, tanh.goといった全ての数学関数において、関数名の先頭文字が小文字から大文字に変更されました(例: asin -> Asin)。これにより、これらの関数はmathパッケージの外部から直接呼び出すことが可能になり、Goの標準ライブラリとしてのmathパッケージの有用性が大幅に向上しました。

  2. 短縮変数宣言 (:=) の導入: 各関数の内部で、varキーワードを用いて型を明示的に指定していた変数宣言の多くが、:=演算子を用いた短縮変数宣言に置き換えられました。 例:

    • var temp, x float64; -> var temp, x float64; の行が削除され、temp, x := sys.modf(x); のように初期化時に:=が使用される。
    • var argsq, value float64; -> argsq := arg*arg; これは、コードの冗長性を減らし、より現代的でGoらしい記述スタイルへの移行を意味します。
  3. パッケージインポートの簡潔化: import math "math"のように、パッケージ名とエイリアスが同じ場合にエイリアスを省略し、import "math"と記述するように変更されました。これはGoの慣用句に従った変更であり、コードの簡潔さに貢献します。

  4. テストフレームワークの全面的な移行:

    • 既存のカスタムテストファイルtest/mathtest.goが削除されました。このファイルは、fmt.sprintfpanicを用いた独自のテスト検証ロジック(ck関数)を持っていました。
    • 新たにsrc/lib/math/test.goが追加されました。この新しいテストファイルは、Go標準のtestingパッケージをインポートし、TestAsin, TestAtanなどの標準的なテスト関数を定義しています。テストの検証にはt.Errorfが使用され、期待値と実際の値が異なる場合にエラーを報告します。
    • テストデータ(vf, asin, atanなど)も、test/mathtest.goからsrc/lib/math/test.goに移動され、var宣言からvar宣言に変わっていますが、これはテストデータとしての配列の初期化方法の変更です。 この移行により、mathパッケージのテストはGoのエコシステムに完全に統合され、go testコマンドで簡単に実行できるようになりました。また、testingパッケージが提供する豊富な機能(テストの並列実行、ベンチマークなど)を活用できるようになります。
  5. 細かなコードの最適化と修正:

    • fmod.gofmod関数内で、r = x;r := x;に変更され、sign変数の初期化もsign := false;に変更されています。
    • hypot.gohypot関数内で、r = p; p = q; q = r;のような一時変数を使ったスワップが、Goの多重代入機能を使ったp, q = q, p;に置き換えられています。
    • sqrt.gosqrt関数内で、ループの初期化がfor i=0; i<=4; i=i+1からfor i:=0; i<=4; i++に変更され、よりGoらしいイテレーションの記述になっています。

これらの変更は、Go言語の設計原則である「シンプルさ」「明瞭さ」「効率性」をmathパッケージに適用し、Go言語の標準ライブラリとしての品質と使いやすさを向上させるための重要なステップでした。

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

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

  1. 関数名の変更(エクスポート): src/lib/math内の各ファイルで、export funcに続く関数名が小文字から大文字に変更されています。

    例1: src/lib/math/asin.go

    --- a/src/lib/math/asin.go
    +++ b/src/lib/math/asin.go
    @@ -4,7 +4,7 @@
     
     package math
     
    -import	math "math"
    +import "math"
     
     /*
      * asin(arg) and acos(arg) return the arcsin, arccos,
    @@ -18,9 +18,7 @@ const
     	pio2 = .15707963267948966192313216e1
     )
     
    -export func
    -asin(arg float64)float64
    -{\n
    +export func Asin(arg float64) float64 {
     	var temp, x float64;
     	var sign bool;
     
    @@ -34,11 +32,11 @@ asin(arg float64)float64
     		return sys.NaN();
     	}
     
    -\ttemp = sqrt(1 - x*x);\n
    +\ttemp = Sqrt(1 - x*x);
     	if x > 0.7 {\n
    -\t\ttemp = pio2 - atan(temp/x);\n
    +\t\ttemp = pio2 - Atan(temp/x);
     	} else {\n
    -\t\ttemp = atan(x/temp);\n
    +\t\ttemp = Atan(x/temp);
     	}
     
     	if sign {\n
    @@ -47,11 +45,9 @@ asin(arg float64)float64
     	return temp;
     }
     
    -export func
    -acos(arg float64)float64
    -{\n
    +export func Acos(arg float64) float64 {
     	if(arg > 1 || arg < -1) {\n
     		return sys.NaN();
     	}
    -\treturn pio2 - asin(arg);\n
    +\treturn pio2 - Asin(arg);
     }
    
  2. 短縮変数宣言 (:=) の導入と冗長なvar宣言の削除: 関数内部の変数宣言がvarから:=に置き換えられています。

    例2: src/lib/math/exp.go

    --- a/src/lib/math/exp.go
    +++ b/src/lib/math/exp.go
    @@ -4,7 +4,7 @@
     
     package math
     
    -import	math "math"
    +import "math"
     
     /*
      * exp returns the exponential func of its
    @@ -26,12 +26,7 @@ const
     	maxf	= 10000;
     )
     
    -export func
    -exp(arg float64) float64
    -{\n
    -\tvar x, fract, temp1, temp2, xsq float64;\n
    -\tvar ent int;\n
    -\n
    +export func Exp(arg float64) float64 {
     	if arg == 0. {\n
     		return 1;
     	}
    @@ -42,11 +37,11 @@ exp(arg float64) float64
     		return sys.Inf(1)
     	}
     
    -\tx = arg*log2e;\n
    -\tent = int(floor(x));\n
    -\tfract = (x-float64(ent)) - 0.5;\n
    -\txsq = fract*fract;\n
    -\ttemp1 = ((p2*xsq+p1)*xsq+p0)*fract;\n
    -\ttemp2 = ((xsq+q2)*xsq+q1)*xsq + q0;\n
    +\tx := arg*log2e;
    +\tent := int(Floor(x));
    +\tfract := (x-float64(ent)) - 0.5;
    +\txsq := fract*fract;
    +\ttemp1 := ((p2*xsq+p3)*xsq+p2)*xsq+p1)*xsq+p0)*fract;
    +\ttemp2 := ((xsq+q2)*xsq+q1)*xsq + q0;
     	return sys.ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent);
     }
    
  3. テストファイルの移動と標準testingパッケージへの移行: test/mathtest.goが削除され、src/lib/math/test.goが新規作成されています。

    例3: src/lib/math/test.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.
    
    // $G $F.go && $L $F.$A && (./$A.out || echo BUG: math fails)
    
    package math
    
    import (
    	"math";
    	"testing";
    )
    
    // ... (テストデータとClose関数) ...
    
    export func TestAsin(t *testing.T) {
    	for i := 0; i < len(vf); i++ {
    		if f := math.Asin(vf[i]/10); !Close(asin[i], f) {
    			t.Errorf("math.Asin(%g) = %g, want %g\n", vf[i]/10, f, asin[i]);
    		}
    	}
    }
    
    // ... (他のTest関数) ...
    

コアとなるコードの解説

このコミットのコアとなるコード変更は、Go言語の設計思想と慣習に深く根ざしています。

  1. 関数名のエクスポート: Go言語では、パッケージの外部から利用されるべき関数や型は、その名前を大文字で始める必要があります。この変更により、mathパッケージ内のAsin, Atan, Exp, Floor, Log, Pow, Sin, Sinh, Sqrt, Tan, Tanh, Fabs, Ceil, Fmod, Hypot, Log10, Pow10, Cosといった主要な数学関数が、Goプログラムのどこからでもmath.Asin(...)のように直接呼び出せるようになりました。これは、mathパッケージがGoの標準ライブラリとして機能するために不可欠な変更であり、Go言語のモジュール性と再利用性を高める上で極めて重要です。

  2. 短縮変数宣言 (:=) の活用: varキーワードと型名を省略した:=演算子による短縮変数宣言は、Go言語で推奨されるイディオムの一つです。これにより、コードがより簡潔になり、特にローカル変数の宣言と初期化が頻繁に行われる場合に、記述量を減らし、可読性を向上させます。コンパイラが型を推論するため、開発者は型の指定に煩わされることなく、ロジックに集中できます。この変更は、Go言語の「簡潔さ」という設計原則を体現しています。

  3. 標準testingパッケージへの移行: test/mathtest.goで用いられていたカスタムのテストロジックは、Go言語が提供する標準のtestingパッケージに置き換えられました。

    • 一貫性: testingパッケージを使用することで、Goプロジェクト全体でテストコードの記述方法に一貫性が生まれます。
    • ツールとの統合: go testコマンドはtestingパッケージと密接に連携しており、テストの発見、実行、結果のレポートを自動化します。これにより、開発ワークフローが効率化されます。
    • 機能の拡張性: testingパッケージは、テストの並列実行、ベンチマークテスト、例(Example)テストなど、豊富な機能を提供します。カスタムテストフレームワークではこれらの機能を独自に実装する必要がありましたが、標準パッケージを利用することで、これらの恩恵を容易に享受できます。 この移行は、Go言語のテスト文化を確立し、開発者が信頼性の高いコードを効率的に書けるようにするための基盤を築きました。

これらの変更は、単なるコードの修正に留まらず、Go言語がその初期段階から、明確な設計原則と開発者の生産性を重視したエコシステムを構築しようとしていたことを強く示しています。

関連リンク

参考にした情報源リンク

  • GitHub: golang/go commit 88daac7862531c606345787f2adff6cf845808d7
  • Go言語の公式ドキュメント(Effective Go, Language Specification, testingパッケージドキュメント)
  • Go言語の可視性ルールに関する一般的な知識
  • Go言語の短縮変数宣言に関する一般的な知識
  • Go言語のテストに関する一般的な知識
  • コミットメッセージと差分からの直接的なコード分析