[インデックス 10615] ファイルの概要
このコミットは、Go言語の標準ライブラリである strconv
パッケージのAPIを刷新し、より一貫性のある命名規則と機能統合を導入するものです。文字列と数値、真偽値、引用符付き文字列間の変換を行う関数群が広範囲にわたって変更されています。
コミット
commit efbeaedb64e426f6874468ea4095d509622514df
Author: Russ Cox <rsc@golang.org>
Date: Mon Dec 5 15:48:21 2011 -0500
strconv: new API
R=golang-dev, bradfitz, gri, r, agl
CC=golang-dev
https://golang.org/cl/5434095
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/efbeaedb64e426f6874468ea4095d509622514df
元コミット内容
strconv: new API
変更の背景
このコミットの主な背景は、Go言語の strconv
パッケージにおけるAPIの一貫性と使いやすさの向上です。以前のAPIは、文字列から数値への変換(Ato*
)、数値から文字列への変換(*toa
)、特定のビットサイズへの変換(*N
)など、機能ごとに異なる命名規則が混在していました。これにより、開発者がどの関数を使用すべきか迷う可能性がありました。
この変更は、以下の目的を達成するために行われました。
- 命名規則の統一:
Parse*
(文字列から型へ)、Format*
(型から文字列へ)、Append*
(バイトスライスに文字列形式を追加) という明確な命名規則を導入し、APIの予測可能性を高める。 - 機能の統合: 浮動小数点数や整数のパースにおいて、ビットサイズを引数として渡すことで、複数の専用関数(例:
Atof32
,Atof64
,AtofN
)を単一の関数(ParseFloat
)に統合し、APIの数を削減する。 - 効率性の向上:
Append*
関数群を導入することで、既存のバイトスライスに変換結果を直接追加できるようになり、不要なメモリ割り当てを減らし、パフォーマンスを向上させる。これは、特にループ内で文字列変換を頻繁に行う場合に有効です。 - Go言語のイディオムへの準拠: Go言語の設計思想である「シンプルさ」と「明瞭さ」に沿ったAPIを提供することを目指しています。
これらの変更により、strconv
パッケージはより直感的で、効率的で、Go言語の他の部分との整合性が高まることが期待されます。
前提知識の解説
このコミットの変更内容を理解するためには、以下のGo言語の基本的な概念と strconv
パッケージの役割について理解しておく必要があります。
strconv
パッケージ: Go言語の標準ライブラリの一部で、プリミティブ型(真偽値、整数、浮動小数点数)と文字列の間で変換を行うための機能を提供します。例えば、文字列 "123" を整数 123 に変換したり、浮動小数点数 3.14 を文字列 "3.14" に変換したりする際に使用されます。- 型変換(Parsing/Formatting):
- Parsing (パース): 文字列形式のデータを、対応するGoのデータ型(例:
int
,float64
,bool
)に変換するプロセスです。例えば、"123"
をint(123)
に変換します。 - Formatting (フォーマット): Goのデータ型を、その文字列表現に変換するプロセスです。例えば、
int(123)
を"123"
に変換します。
- Parsing (パース): 文字列形式のデータを、対応するGoのデータ型(例:
- ビットサイズ(bitSize): 整数型や浮動小数点数型が占めるメモリ上のビット数を指します。Goでは、
int8
,int16
,int32
,int64
やfloat32
,float64
など、異なるビットサイズの型が提供されています。strconv
パッケージの変換関数では、このビットサイズを指定することで、変換後の数値が特定の型に収まるように制御できます。 append
関数: Go言語の組み込み関数で、スライスに要素を追加するために使用されます。このコミットで導入されるAppend*
関数は、変換結果の文字列を既存のバイトスライスに効率的に追加するために利用されます。- エラーハンドリング: Go言語では、関数がエラーを返す場合、通常は戻り値の最後の要素として
error
型の値を返します。strconv
パッケージの変換関数も、変換に失敗した場合に*NumError
型のエラーを返します。 - IEEE 754 浮動小数点数標準: 浮動小数点数の表現と演算に関する国際標準です。
strconv
パッケージの浮動小数点数変換は、この標準に準拠しています。特に、丸め処理(unbiased rounding)は、最も近い偶数への丸め(round half to even)を意味し、統計的なバイアスを避けるために使用されます。
これらの知識があることで、コミットがなぜ特定の関数名を変更し、新しい引数を導入し、特定の関数を追加したのかを深く理解することができます。
技術的詳細
このコミットは、strconv
パッケージのAPIを大幅に再設計しています。主要な変更点は以下の通りです。
-
命名規則の統一と機能の統合:
- 真偽値変換:
Atob(str string) (value bool, err error)
はParseBool(str string) (value bool, err error)
に変更されました。Btoa(b bool) string
はFormatBool(b bool) string
に変更されました。- 新たに
AppendBool(dst []byte, b bool) []byte
が追加され、バイトスライスへの効率的な追加が可能になりました。
- 浮動小数点数変換:
Atof32(s string) (f float32, err error)
,Atof64(s string) (f float64, err error)
,AtofN(s string, n int) (f float64, err error)
の3つの関数が、単一のParseFloat(s string, bitSize int) (f float64, err error)
に統合されました。bitSize
引数(32または64)によって、パースする浮動小数点数の精度を指定します。戻り値は常にfloat64
ですが、bitSize=32
の場合はfloat32
に変換しても値が変わらないことが保証されます。Ftoa32(f float32, fmt byte, prec int) string
,Ftoa64(f float64, fmt byte, prec int) string
,FtoaN(f float64, fmt byte, prec int, n int) string
の3つの関数が、単一のFormatFloat(f float64, fmt byte, prec int, bitSize int) string
に統合されました。同様にbitSize
引数で元の浮動小数点数の精度を指定します。- 新たに
AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte
が追加されました。
- 整数変換:
Btoui64(s string, b int) (n uint64, err error)
はParseUint(s string, base int, bitSize int) (n uint64, err error)
に変更されました。bitSize
引数(0, 8, 16, 32, 64)で、結果が収まるべき符号なし整数型を指定します。bitSize=0
はint
またはuint
のデフォルトサイズを意味します。Btoi64(s string, base int) (i int64, err error)
はParseInt(s string, base int, bitSize int) (i int64, err error)
に変更されました。同様にbitSize
引数で符号付き整数型を指定します。Atoui64
,Atoui
,Atoi64
,Atoi
といった特定の型や基数に特化した関数は削除または簡略化され、ParseUint
やParseInt
のラッパーとして再定義されました。例えば、Atoi(s string) (i int, err error)
はParseInt(s, 10, 0)
のショートハンドとなりました。Uitob64(u uint64, base uint) string
はFormatUint(i uint64, base int) string
に変更されました。Itob64(i int64, base uint) string
はFormatInt(i int64, base int) string
に変更されました。Itoa64
,Uitoa64
,Uitob
,Itob
,Uitoa
といった関数は削除または簡略化され、FormatUint
やFormatInt
のラッパーとして再定義されました。- 新たに
AppendInt(dst []byte, i int64, base int) []byte
とAppendUint(dst []byte, i uint64, base int) []byte
が追加されました。
- 引用符付き文字列変換:
Quote
,QuoteToASCII
,QuoteRune
,QuoteRuneToASCII
に対応するAppendQuote
,AppendQuoteToASCII
,AppendQuoteRune
,AppendQuoteRuneToASCII
関数が追加されました。これらは、変換結果を既存のバイトスライスに直接追加します。
- 真偽値変換:
-
IntSize
定数の変更:- 以前は
computeIntsize()
関数で実行時に計算されていたIntSize
(int
およびuint
のビット数)が、コンパイル時に決定される定数const intSize = 32 << uint(^uint(0)>>63)
に変更されました。これは、Goのコンパイラがターゲットアーキテクチャのポインタサイズに基づいてint
のサイズを決定できるようになったためです。^uint(0)
はすべてのビットが1のuint
値を生成し、>>63
はその値が64ビットシステムでは0、32ビットシステムでは1になることを利用して、シフト量を調整しています。
- 以前は
これらの変更により、strconv
パッケージのAPIはより統一され、柔軟性が増し、パフォーマンスが向上しました。特に、bitSize
引数の導入により、異なる数値型への変換を単一の関数で扱えるようになった点は大きな改善です。また、Append*
関数群は、文字列操作におけるメモリ効率を高める上で重要な役割を果たします。
コアとなるコードの変更箇所
このコミットでは、src/pkg/strconv
ディレクトリ内の複数のファイルが変更されています。主要な変更箇所は以下の通りです。
src/pkg/strconv/atob.go
:Atob
関数がParseBool
にリネーム。Btoa
関数がFormatBool
にリネーム。AppendBool
関数が新規追加。
src/pkg/strconv/atof.go
:Atof32
,Atof64
,AtofN
関数が削除され、ParseFloat
関数が新規追加。ParseFloat
はbitSize
引数を受け取る。- 内部関数
atof32
とatof64
が追加され、ParseFloat
から呼び出される。
src/pkg/strconv/atoi.go
:Btoui64
関数がParseUint
にリネームされ、bitSize
引数が追加。Btoi64
関数がParseInt
にリネームされ、bitSize
引数が追加。Atoui64
,Atoui
,Atoi64
,Atoi
関数が削除または簡略化され、ParseUint
やParseInt
のラッパーとして再定義。IntSize
が実行時計算からコンパイル時定数に変更。
src/pkg/strconv/ftoa.go
:Ftoa32
,Ftoa64
,FtoaN
関数が削除され、FormatFloat
関数が新規追加。FormatFloat
はbitSize
引数を受け取る。AppendFloat
関数が新規追加。
src/pkg/strconv/itoa.go
:Uitob64
関数がFormatUint
にリネームされ、base
引数の型がuint
からint
に変更。Itob64
関数がFormatInt
にリネームされ、base
引数の型がuint
からint
に変更。Itoa64
,Uitoa64
,Uitob
,Itob
,Uitoa
関数が削除または簡略化され、FormatUint
やFormatInt
のラッパーとして再定義。AppendInt
およびAppendUint
関数が新規追加。
src/pkg/strconv/quote.go
:AppendQuote
,AppendQuoteToASCII
,AppendQuoteRune
,AppendQuoteRuneToASCII
関数が新規追加。
- 対応する
_test.go
ファイル群:- 上記API変更に伴い、各テストファイル内の関数呼び出しやテストケースが新しいAPIに合わせて更新されています。
これらの変更は、strconv
パッケージ全体のAPI設計思想を根本的に変更するものであり、Go言語の進化における重要なステップの一つと言えます。
コアとなるコードの解説
ここでは、変更された主要な関数とその意図について、具体的なコードスニペットを交えながら解説します。
ParseBool
(旧 Atob
)
// 旧: func Atob(str string) (value bool, err error) { ... }
// 新: func ParseBool(str string) (value bool, err error) {
// switch str {
// case "1", "t", "T", "true", "TRUE", "True":
// return true, nil
// case "0", "f", "F", "false", "FALSE", "False":
// return false, nil
// }
// return false, &NumError{str, ErrSyntax}
// }
Atob
から ParseBool
へのリネームは、文字列を真偽値に「パースする」という関数の役割をより明確に示しています。Go言語の標準ライブラリでは、文字列から値を変換する関数には Parse
プレフィックスを使用する慣習があります。
ParseFloat
(旧 Atof32
, Atof64
, AtofN
)
// 旧: func Atof32(s string) (f float32, err error) { ... }
// 旧: func Atof64(s string) (f float64, err error) { ... }
// 旧: func AtofN(s string, n int) (f float64, err error) { ... }
// 新: func ParseFloat(s string, bitSize int) (f float64, err error) {
// if bitSize == 32 {
// f1, err1 := atof32(s) // 内部関数
// return float64(f1), err1
// }
// f1, err1 := atof64(s) // 内部関数
// return f1, err1
// }
これは最も重要な変更点の一つです。異なるビットサイズの浮動小数点数パースを ParseFloat
という単一の関数に統合しました。bitSize
引数によって、32ビット(float32
)または64ビット(float64
)の精度でパースするかを指定します。これにより、APIの複雑さが大幅に軽減され、開発者はより汎用的な関数を使用できるようになりました。戻り値が常に float64
であるのは、Goの型システムにおける浮動小数点数の扱いを簡素化するためです。
ParseUint
(旧 Btoui64
) と ParseInt
(旧 Btoi64
)
// 旧: func Btoui64(s string, b int) (n uint64, err error) { ... }
// 新: func ParseUint(s string, b int, bitSize int) (n uint64, err error) { ... }
// 旧: func Btoi64(s string, base int) (i int64, err error) { ... }
// 新: func ParseInt(s string, base int, bitSize int) (i int64, err error) { ... }
整数パース関数も ParseFloat
と同様に bitSize
引数を導入し、特定のビットサイズ(8, 16, 32, 64)の整数をパースできるようになりました。これにより、Atoui
, Atoi
などの特定の型に特化した関数が不要になり、APIが整理されました。base
引数は、数値の基数(2進数から36進数まで)を指定します。
FormatFloat
(旧 Ftoa32
, Ftoa64
, FtoaN
)
// 旧: func Ftoa32(f float32, fmt byte, prec int) string { ... }
// 旧: func Ftoa64(f float64, fmt byte, prec int) string { ... }
// 旧: func FtoaN(f float64, fmt byte, prec int, n int) string { ... }
// 新: func FormatFloat(f float64, fmt byte, prec int, n int) string {
// if n == 32 {
// return genericFtoa(uint64(math.Float32bits(float32(f))), fmt, prec, &float32info)
// }
// return genericFtoa(math.Float64bits(f), fmt, prec, &float64info)
// }
浮動小数点数のフォーマットも FormatFloat
に統合され、bitSize
引数で元の浮動小数点数の精度を指定できるようになりました。これにより、正確な丸め処理と桁数の決定が可能になります。
Append*
関数群
// 例: AppendBool
// func AppendBool(dst []byte, b bool) []byte {
// if b {
// return append(dst, "true"...)
// }
// return append(dst, "false"...)
// }
// 例: AppendInt
// func AppendInt(dst []byte, i int64, base int) []byte {
// return append(dst, FormatInt(i, base)...)
// }
// 例: AppendQuote
// func AppendQuote(dst []byte, s string) []byte {
// return append(dst, Quote(s)...)
// }
Append*
関数群は、既存のバイトスライス dst
に変換結果の文字列を追加し、拡張されたバイトスライスを返す新しいパターンです。これは、特にパフォーマンスが重要なアプリケーションにおいて、文字列変換のたびに新しい文字列を生成するオーバーヘッドを削減するために導入されました。これにより、メモリ割り当てが減り、ガベージコレクションの負荷が軽減されます。
これらの変更は、strconv
パッケージのAPIをより現代的で、Go言語のイディオムに沿ったものにし、開発者にとってより使いやすく、効率的なものにすることを目的としています。
関連リンク
- Go言語公式ドキュメント: https://golang.org/pkg/strconv/
- Go言語のコミット履歴: https://github.com/golang/go/commits/master
参考にした情報源リンク
- Go言語のコミット: https://github.com/golang/go/commit/efbeaedb64e426f6874468ea4095d509622514df
- Go Code Review Comments (API Design): https://go.dev/doc/effective_go#Getters (一般的なGoのAPI設計原則)
- IEEE 754 Standard for Floating-Point Arithmetic: https://standards.ieee.org/ieee/754/6210/ (浮動小数点数に関する背景知識)
- Go言語の
append
関数に関するドキュメント: https://go.dev/blog/slices (スライスとappend
の動作に関する詳細) - Go言語の
int
型のサイズに関する議論 (当時の背景): https://go.dev/doc/faq#int_size (Goのint
型のサイズがプラットフォーム依存であることに関する情報)