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

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

このコミットは、Go言語の標準ライブラリであるstrconvパッケージのドキュメンテーションを大幅に改善することを目的としています。strconvパッケージは、文字列と基本的なデータ型(数値、真偽値など)の間での変換機能を提供します。このコミットでは、既存の関数に詳細なコメントを追加し、一部の関数の引数順序を変更することで、APIの明確性と使いやすさを向上させています。

コミット

commit 5bf0fbe7a8a3c3199956cf6f796b26074076ab1a
Author: Russ Cox <rsc@golang.org>
Date:   Thu Mar 5 15:29:04 2009 -0800

    strconv: doc
    
    R=r
    DELTA=110  (64 added, 19 deleted, 27 changed)
    OCL=25761
    CL=25782
---
 src/lib/strconv/atof.go  | 32 ++++++++++++++++++-------------\
 src/lib/strconv/atoi.go  | 49 ++++++++++++++++++++++++++++--------------------\
 src/lib/strconv/ftoa.go  | 23 +++++++++++++++++++++++
 src/lib/strconv/itoa.go  |  7 ++++---\
 src/lib/strconv/quote.go |  6 ++++++\
 5 files changed, 81 insertions(+), 36 deletions(-)

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

https://github.com/golang/go/commit/5bf0fbe7a8a3c3199956cf6f796b26074076ab1a

元コミット内容

このコミットの元の内容は、非常に簡潔に「strconv: doc」とだけ記されています。これは、strconvパッケージに対するドキュメンテーションの追加が主な変更点であることを示唆しています。

変更の背景

Go言語は、その設計思想として「シンプルさ」と「明確さ」を重視しています。初期のGo言語開発段階において、標準ライブラリのAPIは機能が実装されていく一方で、その利用方法や挙動に関する詳細なドキュメンテーションが不足していることがありました。特に、文字列と数値の変換を行うstrconvパッケージのような基本的なユーティリティは、開発者が頻繁に利用するため、その挙動が明確に定義され、ドキュメント化されていることが極めて重要です。

このコミットは、以下の目的のために行われました。

  1. APIの明確化: 各関数の目的、引数、戻り値、エラー条件などを詳細に記述することで、開発者が関数を正しく理解し、利用できるようにする。
  2. エラーハンドリングの指針: os.EINVALos.ERANGEといった特定のエラーがどのような状況で返されるかを明記し、適切なエラーハンドリングを促す。
  3. 一貫性の向上: strconvパッケージ内の関数間でドキュメンテーションのスタイルと詳細度を統一する。
  4. 引数順序の改善: Btoui64関数の引数順序を、より直感的で一般的なパターン(変換対象の文字列が先に来る)に変更し、APIの一貫性を高める。これは単なるドキュメンテーションの追加だけでなく、APIの使いやすさに関わる重要な変更です。

これらの改善は、Go言語が成熟していく過程で、ライブラリの品質と開発者体験を向上させるための継続的な取り組みの一環として行われました。

前提知識の解説

strconvパッケージ

strconvパッケージは、Go言語の標準ライブラリの一部であり、文字列とGoの組み込みデータ型(ブール値、整数、浮動小数点数)の間で変換を行うための機能を提供します。例えば、文字列"123"を整数123に変換したり、浮動小数点数3.14を文字列"3.14"に変換したりする際に使用されます。

主要な機能カテゴリは以下の通りです。

  • 文字列から数値への変換: Atoi (文字列からintへ), ParseInt (文字列からint64へ、基数指定可能), ParseFloat (文字列からfloatへ) など。
  • 数値から文字列への変換: Itoa (intから文字列へ), FormatInt (int64から文字列へ、基数指定可能), FormatFloat (floatから文字列へ、フォーマット指定可能) など。
  • 真偽値の変換: ParseBool, FormatBool
  • クォーティング: 文字列をGoの文字列リテラル形式に変換するQuoteなど。

IEEE 754 浮動小数点数標準

浮動小数点数の変換(AtofFtoa関連)では、IEEE 754標準が重要な役割を果たします。これは、浮動小数点数の表現と演算に関する国際標準です。

  • 単精度 (float32): 32ビットで表現され、約7桁の10進精度を持ちます。
  • 倍精度 (float64): 64ビットで表現され、約15-17桁の10進精度を持ちます。

strconvパッケージの浮動小数点数変換関数は、この標準に従って丸め処理(IEEE754 unbiased rounding)やオーバーフロー/アンダーフローの検出を行います。特に、文字列から浮動小数点数への変換では、入力文字列が正確に表現できない場合、最も近い浮動小数点数に丸められます。

基数変換 (Radix Conversion)

整数変換(AtoiItoa関連)では、数値の基数(進数)が関係します。

  • 10進数 (Decimal): 日常的に使用される基数10のシステム。
  • 8進数 (Octal): 基数8のシステム。Goでは0で始まる数値リテラルで表現されます(例: 0755)。
  • 16進数 (Hexadecimal): 基数16のシステム。Goでは0xまたは0Xで始まる数値リテラルで表現されます(例: 0xFF)。

strconvパッケージの関数は、これらの基数での文字列表現と数値表現の間の変換をサポートしています。

Go言語のエラーハンドリング

Go言語では、エラーは多値戻り値の最後の値として返されるのが一般的です。strconvパッケージの変換関数もこのパターンに従い、変換が成功した場合はnilを、失敗した場合は*os.Error型の値を返します。

  • os.EINVAL: 無効な引数、または構文的に不正な入力文字列が与えられた場合に返されます。
  • os.ERANGE: 変換結果が対象の型で表現できる範囲を超えている(オーバーフローまたはアンダーフロー)場合に返されます。

技術的詳細

このコミットは、主にstrconvパッケージ内の以下の主要な変換関数にドキュメンテーションを追加しています。

  1. 浮動小数点数変換 (atof.go, ftoa.go):

    • Atof32, Atof64: 文字列をそれぞれfloat32float64に変換します。ドキュメントでは、入力文字列の構文が不正な場合のos.EINVAL、値が範囲外の場合のos.ERANGEの返却条件が明確化されました。また、IEEE754の丸め規則についても言及されています。
    • Ftoa32, Ftoa64: float32float64を文字列に変換します。フォーマット('b', 'e', 'f', 'g')と精度(prec)の指定方法が詳細に説明されています。特に、prec = -1が「Atof32fを正確に返すために必要な最小桁数」を意味することが明記されました。
    • Atof, Ftoa: float型(Goのfloatfloat32またはfloat64のエイリアス)に対する汎用的な変換関数であり、内部的にFloatSize変数に基づいてAtof32/Atof64またはFtoa32/Ftoa64を呼び出すことが説明されています。
  2. 整数変換 (atoi.go, itoa.go):

    • Btoui64: 任意の基数(2〜36)の文字列をuint64に変換します。この関数は、引数の順序が(base int, s string)から(s string, b int)に変更されました。 これは、変換対象の文字列sが第一引数に来るという、Goの他の多くの変換関数(例: ParseInt)との一貫性を高めるための重要なAPI変更です。ドキュメントでは、基数の範囲、空文字列、無効な桁、およびオーバーフロー(os.ERANGE)の条件が詳細に記述されました。
    • Atoui64, Atoi64: 文字列をそれぞれuint64int64に変換します。0xプレフィックスによる16進数、0プレフィックスによる8進数、それ以外は10進数として解釈されることが明記されました。エラー条件(空文字列、無効な桁、範囲外)も詳細化されています。
    • Atoui, Atoi: Atoui64Atoi64と同様ですが、結果をそれぞれuintint型で返します。uintintの最大値を超える場合のos.ERANGEの扱いについても言及されています。
    • Itob64, Itoa64: int64を任意の基数または10進数の文字列に変換します。
    • Itob, Itoa: intを任意の基数または10進数の文字列に変換します。
  3. クォーティング (quote.go):

    • Quote: 文字列をGoのダブルクォートされた文字列リテラル形式に変換します。制御文字や非ASCII文字がGoのエスケープシーケンス(例: \t, \n, \xFF, \u0100)に変換されることが説明されています。
    • CanBackquote: 文字列がバッククォート( `)で囲まれたGoの文字列リテラルとして有効であるかどうかを判定します。バッククォート文字列リテラルは、改行や特殊文字をそのまま含めることができるため、エスケープが不要な場合に便利です。この関数は、文字列内にバッククォート文字や制御文字が含まれていないかをチェックします。

全体として、このコミットはstrconvパッケージのAPIドキュメンテーションを大幅に強化し、開発者がこれらの変換関数をより安全かつ効果的に使用できるようにするための基盤を築いています。特にBtoui64の引数順序変更は、APIの一貫性を高める上で重要な改善点です。

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

このコミットにおける最も顕著な変更は、既存の関数定義に詳細なコメント(GoDoc)が追加されたことです。また、Btoui64関数の引数順序が変更されています。

以下に、src/lib/strconv/atoi.goにおけるBtoui64関数の変更を例として示します。

変更前 (src/lib/strconv/atoi.go):

// Convert arbitrary base string to unsigned integer.
func Btoui64(base int, s string) (n uint64, err *os.Error) {
	if base < 2 || base > 36 || len(s) < 1 {
		return 0, os.EINVAL;
	}

	n = 0;
	cutoff := cutoff64(base);

	for i := 0; i < len(s); i++ {
		var v byte;
		switch {
		case '0' <= s[i] && s[i] <= '9':
			v = s[i] - '0';
		case 'a' <= s[i] && s[i] <= 'z':
			v = s[i] - 'a' + 10;
		case 'A' <= s[i] && s[i] <= 'Z':
			v = s[i] - 'A' + 10;
		default:
			return 0, os.EINVAL;
		}
		if int(v) >= base {
			return 0, os.EINVAL;
		}

		if n >= cutoff {
			// n*base overflows
			return 1<<64-1, os.ERANGE;
		}
		n *= uint64(base);

		n1 := n+uint64(v);
		if n1 < n {
			// n+v overflows
			return 1<<64-1, os.ERANGE;
		}
		n = n1;
	}
	return n, nil;
}

変更後 (src/lib/strconv/atoi.go):

// Btoui64 interprets a string s in an arbitrary base b (2 to 36)
// and returns the corresponding value n.
//
// Btoui64 returns err == os.EINVAL if b is out of
// range or s is empty or contains invalid digits.
// It returns err == os.ERANGE if the value corresponding
// to s cannot be represented by a uint64.
func Btoui64(s string, b int) (n uint64, err *os.Error) {
	if b < 2 || b > 36 || len(s) < 1 {
		return 0, os.EINVAL;
	}

	n = 0;
	cutoff := cutoff64(b); // base -> b

	for i := 0; i < len(s); i++ {
		var v byte;
		switch {
		case '0' <= s[i] && s[i] <= '9':
			v = s[i] - '0';
		case 'a' <= s[i] && s[i] <= 'z':
			v = s[i] - 'a' + 10;
		case 'A' <= s[i] && s[i] <= 'Z':
			v = s[i] - 'A' + 10;
		default:
			return 0, os.EINVAL;
		}
		if int(v) >= b { // base -> b
			return 0, os.EINVAL;
		}

		if n >= cutoff {
			// n*b overflows // n*base overflows -> n*b overflows
			return 1<<64-1, os.ERANGE;
		}
		n *= uint64(b); // base -> b

		n1 := n+uint64(v);
		if n1 < n {
			// n+v overflows
			return 1<<64-1, os.ERANGE;
		}
		n = n1;
	}
	return n, nil;
}

コアとなるコードの解説

上記のBtoui64関数の変更は、以下の2つの側面で重要です。

  1. ドキュメンテーションの追加:

    • 変更前は「Convert arbitrary base string to unsigned integer.」という簡潔なコメントしかありませんでした。
    • 変更後には、GoDoc形式で関数の目的、引数sbの意味、そしてos.EINVALos.ERANGEが返される具体的な条件が詳細に記述されています。これにより、開発者はこの関数がどのような入力を期待し、どのようなエラーを返す可能性があるかを一目で理解できるようになります。
  2. 引数順序の変更:

    • 変更前はfunc Btoui64(base int, s string)というシグネチャでした。
    • 変更後にはfunc Btoui64(s string, b int)となり、変換対象の文字列sが第一引数に、基数bが第二引数に来るようになりました。
    • この変更は、Go言語の標準ライブラリにおける一般的なAPI設計パターン(例えば、strings.Contains(s, substr string)のように、操作対象のデータが第一引数に来る)に合わせたものです。これにより、strconvパッケージ内の他の関数(例: ParseInt(s string, base int, bitSize int))との一貫性が向上し、APIの学習コストが低減されます。
    • 引数名の変更(baseからbへ)も、より簡潔な命名規則への移行を示しています。
    • 関数本体内のbase変数の参照もすべてbに更新されています。

このコミットは、単にコメントを追加するだけでなく、APIの使いやすさと一貫性を向上させるための細かな調整も含まれていることを示しています。このような改善は、Go言語のライブラリが長期的にメンテナンスされ、広く利用される上で不可欠な要素です。

関連リンク

参考にした情報源リンク