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

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

このコミットは、Go言語の標準ライブラリであるmath/bigパッケージにおける2つの主要な改善を含んでいます。一つは、パッケージコメントの記述をより正確にし、メソッドのレシーバと戻り値に関する慣習を明確にすることです。もう一つは、math/big/rat.goファイル内のいくつかのメソッドのレシーバ名をzからxに変更し、コードベース全体の一貫性を向上させることです。

コミット

commit d0607221faec743a726cb38e1dd12b337c33a775
Author: Robert Griesemer <gri@golang.org>
Date:   Fri Feb 3 10:17:19 2012 -0800

    math/big: more accurate package comment
    
    Fix some receiver names for consistency.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5624043
---
 src/pkg/math/big/nat.go | 12 +++++++++---\n src/pkg/math/big/rat.go | 42 +++++++++++++++++++++---------------------\n 2 files changed, 30 insertions(+), 24 deletions(-)\n

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

https://github.com/golang/go/commit/d0607221faec743a726cb38e1dd12b337c33a775

元コミット内容

math/big: more accurate package comment

Fix some receiver names for consistency.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5624043

変更の背景

このコミットは、Go言語の標準ライブラリの品質と一貫性を向上させるためのものです。

  1. ドキュメンテーションの精度向上: math/bigパッケージは、任意精度の数値演算を提供する重要なパッケージです。このような基盤となるパッケージのドキュメンテーションは、開発者が正しく、効率的にライブラリを使用するために極めて重要です。以前のパッケージコメントは、メソッドのレシーバと戻り値に関する慣習について、やや一般的な記述に留まっていました。この変更により、特に*Int*Rat型を扱うメソッドの典型的なシグネチャと、それらがどのようにチェイン操作を可能にするか、そして結果以外の型を返すメソッドのレシーバの扱いについて、より具体的で正確な情報が提供されるようになりました。これにより、ユーザーはパッケージの設計思想と使用方法をより深く理解できるようになります。

  2. コードの一貫性の確保: Go言語では、メソッドのレシーバ名に特定の慣習があります。特に、二項演算(例: z = x Op y)ではzを結果、xyをオペランドとして使用することが一般的です。しかし、String()GobEncode()のように、演算結果を生成するのではなく、レシーバ自身の状態を表現したり、エンコードしたりするメソッドの場合、zというレシーバ名は必ずしも適切ではありません。このコミットでは、これらのメソッドのレシーバ名をzからxに変更することで、math/bigパッケージ内のレシーバ名の使用法をより一貫性のあるものにし、コードの可読性とGo言語のイディオムへの準拠を向上させています。これは、大規模なコードベースにおいて、開発者がコードの意図を素早く理解し、誤解を避ける上で非常に重要です。

前提知識の解説

このコミットを理解するためには、以下のGo言語の概念とmath/bigパッケージに関する知識が役立ちます。

  1. Go言語のレシーバ(Receiver): Go言語では、関数を型に関連付けてメソッドを定義します。このとき、メソッドが操作するインスタンスは「レシーバ」として指定されます。レシーバは、関数名の前に括弧で囲んで宣言されます(例: func (r Type) MethodName(...))。レシーバは値型でもポインタ型でも指定できますが、通常、メソッドがレシーバの状態を変更する場合や、大きな構造体をコピーするコストを避けるためにポインタレシーバが使用されます。math/bigパッケージのメソッドは、ほとんどがポインタレシーバを使用しており、これは任意精度の数値型が通常、比較的大きなメモリフットプリントを持つためです。

  2. Go言語におけるレシーバ名の慣習: Go言語のコミュニティでは、レシーバ名に短い単一文字を使用する慣習があります。特に、以下のような慣習が広く用いられています。

    • x, y: 演算のオペランド(入力値)を表す場合。
    • z: 演算の結果(出力値)を表す場合。特に、z = x Op yのような形式のメソッドでよく使われます。
    • r: レシーバ自身を表す一般的な場合。
    • s: 文字列(string)に関連する場合。 このコミットでは、zが結果を表すという慣習から外れるメソッド(例: String())において、レシーバ名をxに変更することで、より適切な慣習に合わせようとしています。
  3. math/bigパッケージ: math/bigパッケージは、Go言語で任意精度の算術演算を可能にするための型を提供します。これは、標準のGoの組み込み型(int, float64など)が持つ固定の精度制限を超える計算が必要な場合に利用されます。

    • Int: 任意精度の符号付き整数を扱います。
    • Rat: 任意精度の有理数(分数)を扱います。これは、分子と分母がそれぞれInt型で表現されます。 このパッケージのメソッドは、通常、結果をレシーバとして受け取り、そのレシーバを返すことで、メソッドチェインを可能にする設計になっています。
  4. gobパッケージ: gobパッケージは、Goのプログラム間でGoの値をエンコードおよびデコードするためのデータ形式を提供します。これは、ネットワーク経由でのデータ転送や、ファイルへの永続化などに使用されます。GobEncodeメソッドは、gob.GobEncoderインターフェースの一部であり、型が自身をgob形式でエンコードする方法を定義するために実装されます。

技術的詳細

このコミットは、src/pkg/math/big/nat.gosrc/pkg/math/big/rat.goの2つのファイルに影響を与えています。

src/pkg/math/big/nat.goにおけるパッケージコメントの変更

このファイルでは、math/bigパッケージの冒頭にあるコメントが更新されました。変更の目的は、パッケージ内のメソッドのシグネチャに関する慣習をより明確にすることです。

変更前:

// All methods on Int take the result as the receiver; if it is one
// of the operands it may be overwritten (and its memory reused).
// To enable chaining of operations, the result is also returned.

この記述は、Int型(および暗黙的にRat型)のメソッドが結果をレシーバとして受け取り、チェイン操作のためにその結果を返すという一般的なパターンを説明しています。

変更後:

// Methods are typically of the form:
//
//	func (z *Int) Op(x, y *Int) *Int	(similar for *Rat)
//
// and implement operations z = x Op y with the result as receiver; if it
// is one of the operands it may be overwritten (and its memory reused).\n
// To enable chaining of operations, the result is also returned. Methods
// returning a result other than *Int or *Rat take one of the operands as
// the receiver.

新しいコメントは、以下の点を明確にしています。

  • 典型的なシグネチャの例示: func (z *Int) Op(x, y *Int) *Intという具体的な形式を提示し、zが結果、xyがオペランドであることを示しています。これは*Rat型にも同様に適用されます。
  • 結果レシーバの役割: z = x Op yのような演算をレシーバとして実装し、オペランドの一つがレシーバと同じである場合にメモリを再利用できることを強調しています。
  • チェイン操作のサポート: 結果が返されることで、a.Add(b).Mul(c)のようなメソッドチェインが可能になることを再確認しています。
  • *Int/*Rat戻り値のメソッド: 最も重要な追加点は、「*Intまたは*Rat以外の結果を返すメソッドは、オペランドの一つをレシーバとして取る」という新しい慣習を明記したことです。これは、例えばCmp(x *Int) intのような比較メソッドや、String() stringのような文字列変換メソッドなど、結果が数値型ではない場合に、レシーバが演算結果ではなく、主要な入力オペランドとして扱われることを示唆しています。この明確化により、開発者はパッケージの設計原則をより深く理解し、適切なレシーバ名の選択に役立てることができます。

src/pkg/math/big/rat.goにおけるレシーバ名の変更

このファイルでは、Rat型のいくつかのメソッドのレシーバ名がzからxに変更されました。対象となったメソッドは以下の通りです。

  • String() string
  • RatString() string
  • FloatString(prec int) string
  • GobEncode() ([]byte, error)

これらのメソッドは、いずれもRat型のインスタンスを操作して、その文字列表現を返したり、gob形式にエンコードしたりするものです。これらは、AddMulのような二項演算のように「結果zを生成する」という性質のものではありません。むしろ、レシーバ自身(x)を主たる対象として処理を行います。

Go言語の慣習では、zは通常、演算の結果を表すために使用されます。しかし、これらのメソッドは結果を生成するのではなく、レシーバ自身のプロパティを表現するため、xというレシーバ名の方がより適切であると判断されました。この変更により、math/bigパッケージ全体でのレシーバ名の使用法に一貫性がもたらされ、コードの意図がより明確になります。

例えば、func (z *Rat) String() stringfunc (x *Rat) String() stringに変更され、それに伴いメソッド内部のzへの参照がすべてxに置き換えられています。これは純粋なリファクタリングであり、機能的な変更はありませんが、コードの可読性と保守性を向上させます。

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

src/pkg/math/big/nat.go

--- a/src/pkg/math/big/nat.go
+++ b/src/pkg/math/big/nat.go
@@ -8,9 +8,15 @@
 //	- Int	signed integers
 //	- Rat	rational numbers
 //
-// All methods on Int take the result as the receiver; if it is one
-// of the operands it may be overwritten (and its memory reused).\n
-// To enable chaining of operations, the result is also returned.
+// Methods are typically of the form:
+//
+//	func (z *Int) Op(x, y *Int) *Int	(similar for *Rat)
+//
+// and implement operations z = x Op y with the result as receiver; if it
+// is one of the operands it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned. Methods
+// returning a result other than *Int or *Rat take one of the operands as
+// the receiver.
 //
 package big

src/pkg/math/big/rat.go

--- a/src/pkg/math/big/rat.go
+++ b/src/pkg/math/big/rat.go
@@ -328,36 +328,36 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
 }
 
 // String returns a string representation of z in the form "a/b" (even if b == 1).
-func (z *Rat) String() string {
+func (x *Rat) String() string {
 	s := "/1"
-	if len(z.b) != 0 {
-		s = "/" + z.b.decimalString()
+	if len(x.b) != 0 {
+		s = "/" + x.b.decimalString()
 	}
-	return z.a.String() + s
+	return x.a.String() + s
 }
 
 // RatString returns a string representation of z in the form "a/b" if b != 1,
 // and in the form "a" if b == 1.
-func (z *Rat) RatString() string {
-	if z.IsInt() {
-		return z.a.String()
+func (x *Rat) RatString() string {
+	if x.IsInt() {
+		return x.a.String()
 	}
-	return z.String()
+	return x.String()
 }
 
 // FloatString returns a string representation of z in decimal form with prec
 // digits of precision after the decimal point and the last digit rounded.
-func (z *Rat) FloatString(prec int) string {
-	if z.IsInt() {
-		s := z.a.String()
+func (x *Rat) FloatString(prec int) string {
+	if x.IsInt() {
+		s := x.a.String()
 		if prec > 0 {
 			s += "." + strings.Repeat("0", prec)
 		}
 		return s
 	}
-	// z.b != 0
+	// x.b != 0
 
-	q, r := nat(nil).div(nat(nil), z.a.abs, z.b)
+	q, r := nat(nil).div(nat(nil), x.a.abs, x.b)
 
 	p := natOne
 	if prec > 0 {
@@ -365,11 +365,11 @@ func (z *Rat) FloatString(prec int) string {
 	}
 
 	r = r.mul(r, p)
-	r, r2 := r.div(nat(nil), r, z.b)
+	r, r2 := r.div(nat(nil), r, x.b)
 
 	// see if we need to round up
 	r2 = r2.add(r2, r2)
-	if z.b.cmp(r2) <= 0 {
+	if x.b.cmp(r2) <= 0 {
 		r = r.add(r, natOne)
 		if r.cmp(p) >= 0 {
 			q = nat(nil).add(q, natOne)
@@ -378,7 +378,7 @@ func (z *Rat) FloatString(prec int) string {
 	}
 
 	s := q.decimalString()
-	if z.a.neg {
+	if x.a.neg {
 		s = "-" + s
 	}
 
@@ -395,10 +395,10 @@ const ratGobVersion byte = 1
 
 // GobEncode implements the gob.GobEncoder interface.
-func (z *Rat) GobEncode() ([]byte, error) {
-	buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
-	i := z.b.bytes(buf)
-	j := z.a.abs.bytes(buf[0:i])
+func (x *Rat) GobEncode() ([]byte, error) {
+	buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+	i := x.b.bytes(buf)
+	j := x.a.abs.bytes(buf[0:i])
 	n := i - j
 	if int(uint32(n)) != n {
 		// this should never happen
@@ -407,7 +407,7 @@ func (z *Rat) GobEncode() ([]byte, error) {
 	binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
 	j -= 1 + 4
 	b := ratGobVersion << 1 // make space for sign bit
-	if z.a.neg {
+	if x.a.neg {
 		b |= 1
 	}
 	buf[j] = b

コアとなるコードの解説

src/pkg/math/big/nat.goのコメント変更

この変更は、math/bigパッケージのドキュメンテーションを改善するものです。特に、Go言語におけるメソッドのレシーバの役割と、math/bigパッケージが採用している特定の慣習を明確にしています。

  • func (z *Int) Op(x, y *Int) *Int の導入: これは、math/bigパッケージにおける典型的な二項演算メソッドのシグネチャを示しています。ここで、zは演算結果が格納されるレシーバであり、xyは入力オペランドです。メソッドが*Int(または*Rat)を返すことで、result.Add(a, b).Mul(c, d)のように複数の演算をチェインして記述することが可能になります。
  • *Intまたは*Rat以外の結果を返すメソッドは、オペランドの一つをレシーバとして取る」: この新しい記述は非常に重要です。例えば、Cmp(x *Int) intのような比較メソッドは、結果としてint(-1, 0, 1)を返します。このようなメソッドでは、レシーバは演算結果を格納するzではなく、比較の対象となる主要なオペランドとして機能します。この場合、レシーバ名としてxがより適切であるという慣習を示唆しています。この明確化により、開発者はmath/bigパッケージのメソッドシグネチャの背後にある設計原則をより深く理解し、自身のコードで同様のパターンを適用する際の指針とすることができます。

src/pkg/math/big/rat.goのレシーバ名変更

この変更は、Rat型のString(), RatString(), FloatString(), GobEncode()メソッドのレシーバ名をzからxに統一するものです。

  • zからxへの変更の理由: Go言語の慣習では、zは通常、演算の結果を格納するレシーバとして使用されます。しかし、これらのメソッドは演算結果を生成するものではありません。

    • String(), RatString(), FloatString(): これらはRat型のインスタンスの文字列表現を返します。レシーバは、その文字列表現を生成する「対象」であり、演算の「結果」ではありません。
    • GobEncode(): これはRat型のインスタンスをgob形式にエンコードします。ここでも、レシーバはエンコードされる「対象」であり、演算の結果ではありません。 したがって、これらのメソッドにおいてレシーバをxと命名することは、そのレシーバが「主たるオペランド」または「操作の対象」であることをより適切に表現し、Go言語のイディオムに沿ったものとなります。
  • コードへの影響: この変更は純粋なリファクタリングであり、メソッドの機能的な振る舞いには一切影響を与えません。しかし、コードベース全体でレシーバ名の命名規則に一貫性をもたらし、特にmath/bigパッケージのような数値演算ライブラリにおいて、メソッドの役割とレシーバの意図をより明確にすることで、コードの可読性と保守性を大幅に向上させます。開発者は、レシーバ名を見るだけで、そのメソッドが結果を生成する演算なのか、それともレシーバ自身を操作するのかを直感的に理解できるようになります。

関連リンク

  • Gerrit Change-ID: https://golang.org/cl/5624043 (GoプロジェクトのコードレビューシステムであるGerritにおけるこの変更のID)

参考にした情報源リンク

  • Go言語の公式ドキュメンテーション: math/bigパッケージ
  • Go言語のコードレビューコメントやスタイルガイドに関する一般的な情報源 (Goコミュニティの慣習について)