[インデックス 11918] ファイルの概要
このコミットは、Go言語の公式ドキュメントの一部である doc/codewalk/markov.go
ファイルに対する修正です。このファイルは、Goのコードウォーク(チュートリアル)の一部として提供されているマルコフ連鎖を用いたテキスト生成プログラムのサンプルコードです。
コミット
このコミットは、doc/codewalk/markov.go
内で使用されていた time.Nanoseconds()
関数がGo言語のAPIから削除された(または変更された)ことに起因するビルドエラーを修正します。具体的には、乱数ジェネレータのシード設定に使用されていた time.Nanoseconds()
を、現在のGo APIで推奨される time.Now().UnixNano()
に置き換えることで、コードが正しくビルドされるようにします。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/932cdfbc4ce2cebd52bd3f52813a64c8e94217c0
元コミット内容
doc: fix codewalk/markov.go
When I build it, I got:
/home/njubee/work/golang/doc/codewalk/markov.go:124: undefined: time.Nanoseconds
time.Nanoseconds() does not exist now, use time.Now().UnixNano() instead
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5668044
変更の背景
この変更の背景には、Go言語の標準ライブラリ、特にtime
パッケージの進化があります。Go言語は初期のバージョンから活発に開発が進められており、APIの改善や整理が頻繁に行われていました。
コミットメッセージにあるように、time.Nanoseconds()
はビルド時に「undefined」エラーを引き起こしていました。これは、この関数がGoの特定のバージョンで非推奨となり、最終的に削除されたか、あるいはそのシグネチャが変更されたことを意味します。乱数ジェネレータのシードとしてナノ秒単位の現在時刻を使用するという意図は変わらず、そのための新しい、より適切なAPIとして time.Now().UnixNano()
が導入されました。
この修正は、Go言語の進化に伴うAPIの変更に、公式ドキュメント内のサンプルコードが追従するためのメンテナンス作業の一環です。古いAPIを使用していると、ユーザーがドキュメントのコードを試した際にビルドエラーに遭遇し、混乱を招く可能性があるため、このような修正は重要です。
前提知識の解説
1. Go言語のrand
パッケージと乱数生成
Go言語で擬似乱数を生成するには、標準ライブラリのmath/rand
パッケージを使用します。擬似乱数ジェネレータは、内部状態に基づいて乱数のように見える数列を生成します。この内部状態の初期値を「シード(seed)」と呼びます。
rand.Seed(seed int64)
: この関数は、乱数ジェネレータのシードを設定します。同じシード値を与えると、常に同じ乱数列が生成されます。これは再現性が必要なテストなどで役立ちますが、通常は実行ごとに異なる乱数列を得るために、変化する値(例: 現在時刻)をシードとして使用します。
2. Go言語のtime
パッケージと時刻の取得
Go言語で時刻を扱うには、標準ライブラリのtime
パッケージを使用します。
time.Now()
: 現在のローカル時刻をtime.Time
型の値として返します。time.Time.UnixNano()
:time.Time
型のメソッドで、エポック(1970年1月1日UTC)からの経過時間をナノ秒単位でint64
型として返します。この値は非常に細かく、実行ごとに異なる値となるため、乱数ジェネレータのシードとして適しています。
3. time.Nanoseconds()
(旧API)
このコミットの時点では、time.Nanoseconds()
という関数が存在していました(あるいは、存在したが後に削除されたか、time.Now().UnixNano()
に置き換えられた)。これは、おそらく現在のナノ秒単位の時刻を直接返すことを意図した関数だったと考えられます。しかし、Go言語のAPI設計の進化の中で、time.Now().UnixNano()
のように、まずtime.Time
オブジェクトを取得し、そこからナノ秒値を取り出すという、より一貫性のあるアプローチが採用されたため、time.Nanoseconds()
は非推奨となり、最終的に削除されたと推測されます。
技術的詳細
このコミットの技術的な核心は、Go言語のAPI変更への対応です。
Go言語のtime
パッケージは、時間の表現と操作のための基本的な機能を提供します。初期のGoバージョンでは、time.Nanoseconds()
のような関数が直接ナノ秒単位の時刻を返すために存在していた可能性があります。しかし、GoのAPIは、よりオブジェクト指向的で一貫性のある設計へと進化しました。
time.Now()
は現在の時刻を表す time.Time
型の値を返します。この time.Time
型は、時刻に関する様々な情報(年、月、日、時、分、秒、ナノ秒など)をカプセル化しています。UnixNano()
メソッドは、この time.Time
オブジェクトから、Unixエポックからの経過時間をナノ秒単位で int64
型として抽出するための標準的な方法です。
乱数ジェネレータのシードとしてナノ秒単位の現在時刻を使用することは、多くのプログラミング言語で一般的なプラクティスです。これは、プログラムが実行されるたびに異なるシード値が提供され、結果として異なる乱数列が生成されることを保証するためです。これにより、プログラムの動作に予測不可能な要素が導入され、例えばゲームやシミュレーションなどで「ランダム性」が求められる場合に重要となります。
この変更は、単なる関数名の置き換え以上の意味を持ちます。それは、Go言語のAPIがより洗練され、モジュール化された設計へと移行していることを示しています。time.Now()
で time.Time
オブジェクトを取得し、そのオブジェクトのメソッドを呼び出すことで特定の時間情報を取得するというパターンは、Goの標準ライブラリ全体で一貫して見られる設計原則です。
コアとなるコードの変更箇所
--- a/doc/codewalk/markov.go
+++ b/doc/codewalk/markov.go
@@ -120,8 +120,8 @@ func main() {
numWords := flag.Int("words", 100, "maximum number of words to print")
prefixLen := flag.Int("prefix", 2, "prefix length in words")
- flag.Parse() // Parse command-line flags.
- rand.Seed(time.Nanoseconds()) // Seed the random number generator.
+ flag.Parse() // Parse command-line flags.
+ rand.Seed(time.Now().UnixNano()) // Seed the random number generator.
c := NewChain(*prefixLen) // Initialize a new Chain.
c.Build(os.Stdin) // Build chains from standard input.
コアとなるコードの解説
変更は doc/codewalk/markov.go
ファイルの123行目と124行目に集中しています。
変更前:
flag.Parse() // Parse command-line flags.
rand.Seed(time.Nanoseconds()) // Seed the random number generator.
ここでは、コマンドライン引数のパース後、rand.Seed()
関数を呼び出して乱数ジェネレータのシードを設定しています。シード値として time.Nanoseconds()
の戻り値を使用しています。しかし、この time.Nanoseconds()
関数がGoのAPIから削除されたため、ビルドエラーが発生していました。
変更後:
flag.Parse() // Parse command-line flags.
rand.Seed(time.Now().UnixNano()) // Seed the random number generator.
変更後では、time.Nanoseconds()
の代わりに time.Now().UnixNano()
が使用されています。
time.Now()
: 現在の時刻を表すtime.Time
型の値を返します。.UnixNano()
:time.Time
型のメソッドで、その時刻をUnixエポックからのナノ秒数としてint64
型で返します。
この変更により、乱数ジェネレータは引き続き現在のナノ秒単位の時刻でシードされ、実行ごとに異なる乱数列が生成されるという元の意図が維持されます。同時に、Go言語の現在のAPIに準拠し、ビルドエラーが解消されます。
関連リンク
- Go CL 5668044: https://golang.org/cl/5668044
参考にした情報源リンク
- Go言語の公式ドキュメント (
time
パッケージ,math/rand
パッケージ) - Go言語のコミット履歴およびAPI変更に関する情報 (Goのリリースノートやメーリングリストなど)
- 一般的なプログラミングにおける乱数生成とシードの概念に関する知識