[インデックス 12216] ファイルの概要
このコミットは、Go言語の公式ドキュメントの一部である doc/go1.html
および doc/go1.tmpl
ファイルに対する更新です。具体的には、Go 1リリースにおける主要な変更点について、その背景や正当性を説明する議論(justification discussions)が追加されています。これにより、Go 1で導入された言語仕様や標準ライブラリの変更がなぜ行われたのか、その意図がより明確に伝えられるようになります。
コミット
commit 68c7e8a2f431577e77273f1860f3f88dc06627ea
Author: Rob Pike <r@golang.org>
Date: Mon Feb 27 07:31:34 2012 +1100
doc/go1: add justification discussions to major changes
Fixes #3086.
R=golang-dev, gri, r, kevlar
CC=golang-dev
https://golang.org/cl/5700067
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/68c7e8a2f431577e77273f1860f3f88dc06627ea
元コミット内容
このコミットは、Go 1リリースノートのドキュメント (doc/go1.html
と doc/go1.tmpl
) に、Go 1で導入された主要な変更点に関する「正当化の議論(justification discussions)」を追加するものです。これは、単に機能が変更されたことを記述するだけでなく、なぜその変更が必要だったのか、どのような問題が解決されたのか、といった背景情報を提供することを目的としています。
具体的には、以下の項目について説明が追加されています。
append
関数close
関数init
時のGoroutineの挙動rune
型の導入- マップからの要素削除 (
delete
関数) - マップのイテレーション順序のランダム化
- 多重代入の評価順序
- シャドーイングされた変数と
return
文 - エクスポートされていないフィールドを持つ構造体のコピー
- 構造体と配列の等価性比較
error
型とerrors
パッケージ- システムコールエラー (
syscall
パッケージ) time
パッケージの再設計- その他の小さな変更点(
archive/zip
,encoding/xml
,go/doc
など)
変更の背景
Go 1はGo言語の最初の安定版リリースであり、将来にわたる互換性を保証するための重要なマイルストーンでした。このリリースでは、言語の設計を洗練し、標準ライブラリを改善するために多くの変更が導入されました。しかし、これらの変更は既存のコードベースに影響を与える可能性があり、開発者がGo 1への移行をスムーズに行えるように、変更の理由と影響を明確に説明する必要がありました。
このコミットの背景には、Go 1の設計思想、特に「シンプルさ」「安全性」「パフォーマンス」といった原則があります。例えば、init
時のGoroutineの挙動変更は、初期化処理の柔軟性と安全性を向上させるため、rune
型の導入はUnicode文字の適切な処理と将来的なint
型の64ビット化を可能にするため、マップのイテレーション順序のランダム化は、開発者が意図しない順序依存のコードを書くことを防ぐため、といった具体的な理由が存在します。
このコミットは、これらの重要な変更が単なる恣意的なものではなく、明確な設計上の理由と利点に基づいていることを開発者に理解してもらうためのドキュメント改善の一環として行われました。
前提知識の解説
このコミットの変更内容を理解するためには、Go言語の基本的な概念と、Go 1リリース以前のGo言語(r60.3など)の挙動に関する知識が役立ちます。
- Go言語の基本: Goroutine、チャネル、スライス、マップ、構造体、インターフェース、パッケージといったGo言語の基本的なデータ構造と並行処理の概念。
append
関数: スライスに要素を追加するための組み込み関数。close
関数: チャネルを閉じるための組み込み関数。init
関数: パッケージの初期化時に自動的に実行される関数。rune
型: Go言語におけるUnicodeコードポイントを表す型。Go 1以前はint
型がUnicodeコードポイントを表すために使われることが多かった。- マップ: キーと値のペアを格納するデータ構造。Go 1以前はマップのイテレーション順序が定義されていなかった。
- 多重代入: 複数の変数に同時に値を代入するGoの機能。
- シャドーイング: 内側のスコープで外側のスコープの変数と同じ名前の変数を宣言すること。
- エクスポートされていないフィールド: Go言語では、フィールド名が小文字で始まる場合、そのフィールドはパッケージ外からアクセスできない(エクスポートされていない)。
- 等価性比較:
==
および!=
演算子による値の比較。Go 1以前は構造体や配列の等価性比較が定義されていなかった。 error
インターフェース: Go言語におけるエラー処理の標準的なインターフェース。Go 1以前はos.Error
型が使われることが多かった。syscall
パッケージ: オペレーティングシステムのシステムコールにアクセスするためのパッケージ。time
パッケージ: 時間と日付を扱うための標準ライブラリパッケージ。
これらの概念について、Go 1以前の挙動とGo 1での変更点を比較することで、このコミットが追加した「正当化の議論」の意義を深く理解できます。
技術的詳細
このコミットは、doc/go1.html
とdoc/go1.tmpl
という2つのドキュメントファイルを変更しています。これらのファイルは、Go 1のリリースノートを生成するためのソースであり、HTMLとGoのテンプレート構文を組み合わせて記述されています。
変更の主な内容は、既存の各セクションに新たな<p>
タグで囲まれた段落を追加し、Go 1での変更がなぜ行われたのか、その技術的な理由や設計上の考慮事項を詳細に説明することです。
以下に、いくつかの主要な変更点とその技術的詳細の追加内容を抜粋して解説します。
append
関数
- 変更前:
append
は可変引数関数であり、バイトスライスにバイトを追加する際に...
構文を使用できた。しかし、文字列を[]byte
に直接追加する方法がなかった。 - 追加された説明:
append
はバイトスライスに文字列をバイト単位で直接追加できるようになり、変換が不要になった。これにより、文字列とバイトスライスの間の摩擦が軽減された。
close
関数
- 変更前:
close
はチャネルの送信者がこれ以上データを送信しないことを受信者に伝えるための組み込み関数。Go 1以前は、close
が正しく使用されているか(例えば、受信専用チャネルに対してclose
が呼び出されていないか)のコンパイル時チェックがなかった。 - 追加された説明:
close
は送信側のゴルーチンのみが使用することを意図しており、受信専用チャネルに対するclose
の呼び出しはコンパイル時エラーとなるように変更された。これにより、誤用や競合状態を防ぐ。
init
時のGoroutine
- 変更前: 以前の言語仕様では、初期化中に実行される
go
ステートメントはゴルーチンを作成するが、プログラム全体の初期化が完了するまで実行を開始しなかった。これは、init
の有用性を制限し、ライブラリが初期化中にゴルーチンを使用することを避ける必要があった。 - 追加された説明: Go 1では、初期化中にゴルーチンが作成され、すぐに実行されるようになった。これにより、
init
ルーチンやグローバル初期化式からゴルーチンを使用してもデッドロックが発生せず、init
の柔軟性が向上した。これは、言語に対する信頼が高まった結果、以前の設計が不必要であると判断されたため。
rune
型
- 変更前: 以前の言語仕様では
int
型が32ビットまたは64ビット幅を許容していたが、当時の実装では64ビットプラットフォームでもint
は32ビットだった。Unicodeコードポイントもint
で保持されていたため、int
が64ビットに拡張されると、各コードポイントが余分な32ビットのストレージを浪費する問題があった。 - 追加された説明: 64ビット
int
への変更を可能にするため、Go 1では個々のUnicodeコードポイントを表す新しい基本型rune
が導入された。rune
はint32
のエイリアスであり、byte
がuint8
のエイリアスであるのと同様。これにより、int
のサイズ変更がUnicode処理に与える影響を分離できる。
マップからの要素削除 (delete
関数)
- 変更前: マップから要素を削除する構文は
m[k] = value, false
という特殊な形式だった。これは、評価されるが破棄される値と、ほとんど常にfalse
であるブール値を渡す必要があり、奇妙で議論の的となっていた。 - 追加された説明: Go 1では、この構文が廃止され、新しい組み込み関数
delete(m, k)
が導入された。これにより、マップからの要素削除がより直感的で明確になった。
マップのイテレーション順序
- 変更前: 以前の言語仕様では、マップのイテレーション順序が定義されておらず、ハードウェアプラットフォームによって異なる可能性があった。これにより、マップのイテレーションに依存するテストが不安定で移植性が低いものとなっていた。
- 追加された説明: Go 1では、
for range
ステートメントでマップをイテレートする際の要素の訪問順序が意図的にランダム化された。これにより、開発者がイテレーション順序に依存するコードを書くことを防ぎ、早期にバグを発見できるようにする。また、マップの実装がより良いバランスを確保できるようになる。
構造体と配列の等価性
- 変更前: Go 1以前は、構造体と配列の値の等価性が定義されていなかった。これにより、構造体や配列をマップのキーとして使用できなかった。また、関数やマップの等価性比較は定義されていたが、関数はクロージャの存在下で問題があり、マップは内容ではなくポインタを比較するため、ユーザーの意図と異なることが多かった。
- 追加された説明: Go 1では、構造体と配列の値の等価性比較(
==
と!=
)が定義され、それらがマップのキーとして使用できるようになった。ただし、比較可能な要素で構成されている場合に限る。また、関数値の等価性定義はnil
との比較を除いて削除され、マップの等価性もnil
との比較を除いて削除された。
これらの変更は、Go言語の設計原則に基づき、言語の一貫性、安全性、使いやすさを向上させることを目的としています。
コアとなるコードの変更箇所
このコミットは、Go言語のソースコード自体ではなく、Go 1リリースに関するドキュメントのHTMLおよびテンプレートファイルを変更しています。
doc/go1.html
doc/go1.tmpl
これらのファイルは、Go 1の主要な変更点について説明する公式ドキュメントのコンテンツを構成しています。変更は主に、既存のセクションに新たな段落(<p>
タグで囲まれたテキスト)を追加し、各変更の「正当化の議論」を挿入する形で行われています。
例: append
関数に関する変更
--- a/doc/go1.html
+++ b/doc/go1.html
@@ -57,9 +57,11 @@ r60.3). It also explains how to update code from r60 to run under Go 1.
<h3 id="append">Append</h3>
<p>
-The <code>append</code> built-in function is variadic, so one can
-append to a byte slice using the <code>...</code> syntax in the
-call.
+The <code>append</code> predeclared variadic function makes it easy to grow a slice
+by adding elements to the end.
+A common use is to add bytes to the end of a byte slice when generating output.
+However, <code>append</code> did not provide a way to append a string to a <code>[]byte</code>,
+which is another common case.
</p>
<pre><!--{{code "progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
@@ -69,7 +71,8 @@ call.
<p>
By analogy with the similar property of <code>copy</code>, Go 1
permits a string to be appended (byte-wise) directly to a byte
-slice; the conversion is no longer necessary:\n+slice, reducing the friction between strings and byte slices.\n+The conversion is no longer necessary:
</p>
この差分は、append
関数に関する説明に、文字列をバイトスライスに直接追加できなかったという以前の課題と、Go 1でそれが可能になったことで「文字列とバイトスライスの間の摩擦が軽減された」という正当化の議論が追加されていることを示しています。
同様の変更が、close
、init
時のGoroutine、rune
型、マップの削除、マップのイテレーション、多重代入、シャドーイング、構造体のコピー、等価性、エラー処理、システムコール、時間パッケージなど、Go 1の主要な変更点に関するすべてのセクションで行われています。
コアとなるコードの解説
このコミットにおける「コアとなるコード」は、Go 1のリリースノートを構成するHTMLドキュメントとテンプレートファイルです。これらのファイルは、Go言語の変更点とその理由を説明するための情報源として機能します。
変更の目的は、Go 1で導入された各機能や仕様変更について、単に「何が変わったか」だけでなく、「なぜ変わったのか」という背景と正当性を明確にすることです。これにより、Go言語の設計思想と進化の過程を開発者がより深く理解できるようになります。
例えば、マップのイテレーション順序がランダム化されたことについて、このコミットで追加された説明は、以前の挙動がプラットフォーム間で異なり、テストの不安定性や移植性の問題を引き起こしていたことを指摘しています。そして、Go 1でのランダム化は、開発者が意図せずイテレーション順序に依存するコードを書くことを防ぎ、早期にバグを発見できるようにするという設計上の意図を明確にしています。
このように、各変更点に対して、問題提起、Go 1での解決策、そしてその解決策がもたらす利点や設計上の考慮事項が詳細に記述されています。これは、Go言語の透明性と、開発者コミュニティへの情報提供の姿勢を示すものです。
関連リンク
- Go 1 Release Notes (公式ドキュメント): このコミットが更新しているドキュメントの最終版。
- Go言語の公式ウェブサイト:
- Go言語のIssue Tracker (Issue #3086): このコミットが修正したIssue。
参考にした情報源リンク
- コミットメッセージと差分情報 (
./commit_data/12216.txt
) - Go言語の公式ドキュメント (Go 1 Release Notes)
- Go言語の設計に関する一般的な知識