[インデックス 14625] ファイルの概要
このコミットは、Go言語の公式仕様書である doc/go_spec.html
を更新し、配列の長さ、スライスの容量、およびインデックスに使用される定数が、Goの組み込み型である int
の範囲内に収まる必要があることを明確にしています。これにより、コンパイル時の定数評価と実行時の挙動の一貫性が保たれ、特に異なるアーキテクチャ(32ビットと64ビット)間での潜在的な問題が回避されます。
コミット
commit 3906706297a78df69d7f87748963bf375b4c4511
Author: Robert Griesemer <gri@golang.org>
Date: Wed Dec 12 11:06:26 2012 -0800
spec: index and array/slice size constants must fit into an int
R=r, rsc, iant, ken
CC=golang-dev
https://golang.org/cl/6903048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3906706297a78df69d7f87748963bf375b4c4511
元コミット内容
spec: index and array/slice size constants must fit into an int
変更の背景
Go言語では、配列の長さ、スライスの容量、および要素へのインデックスアクセスに定数を使用できます。これらの定数はコンパイル時に評価されます。しかし、Goの int
型は、実行環境のアーキテクチャ(32ビットまたは64ビット)によってサイズが異なります。例えば、32ビットシステムでは int
は32ビットですが、64ビットシステムでは64ビットです。
この差異は、非常に大きな定数(例えば 1 << 63
のような値)が配列の長さやインデックスとして指定された場合に問題を引き起こす可能性がありました。もし定数が int
の最大値を超える場合、その定数で宣言された配列やスライスが、特定のアーキテクチャでは表現できない、あるいは予期せぬ挙動を示す可能性がありました。
このコミットの背景には、Go言語の仕様をより厳密にし、このような定数が常に int
型で表現可能であることを保証することで、コードの移植性と堅牢性を高める目的があります。特に、len
や cap
といった組み込み関数が int
型の値を返すこととの整合性を保つためにも、この明確化が必要でした。
前提知識の解説
- Goの
int
型: Go言語のint
型は、プラットフォームに依存する符号付き整数型です。そのサイズは少なくとも32ビットであり、通常は32ビットシステムでは32ビット、64ビットシステムでは64ビットです。これは、C言語のint
と同様に、効率的な処理のためにCPUのワードサイズに合わせられることが多いです。 - 定数式: Goにおける定数式は、コンパイル時に評価される式です。数値定数は、その値が特定の型に収まる限り、任意の精度で表現できます。しかし、変数の型が決定されると、その値はその型の範囲に制約されます。
- 配列とスライス:
- 配列: 長さが固定された連続したメモリ領域です。配列の長さは型の一部であり、コンパイル時に既知の定数である必要があります。
- スライス: 配列の一部を参照する動的なデータ構造です。スライスは長さ(
len
)と容量(cap
)を持ち、これらは実行時に変更される可能性がありますが、make
関数で初期化する際には定数で指定できます。
- インデックス式: 配列、スライス、文字列の要素にアクセスするために使用される
a[x]
の形式の式です。インデックスx
は整数値でなければならず、0
からlen(a)-1
の範囲内である必要があります。 make
関数: スライス、マップ、チャネルを初期化するために使用される組み込み関数です。スライスの場合、make([]T, length, capacity)
の形式で、初期の長さと容量を定数で指定できます。
技術的詳細
このコミットの主要な変更点は、Go言語仕様の複数のセクションにわたって、「定数」が int
型で表現可能であるという制約を明示的に追加したことです。
-
配列の長さ:
- 以前は「非負の整数値に評価される定数式」とされていましたが、これに加えて「
int
型の値で表現可能な非負の定数」という条件が追加されました。これにより、配列の長さがint
の最大値を超えるような定数で指定されることが禁止されます。
- 以前は「非負の整数値に評価される定数式」とされていましたが、これに加えて「
-
インデックス式:
- 配列、スライス、文字列のインデックスに関するルールが整理され、特に定数インデックスに対して「非負であり、
int
型の値で表現可能でなければならない」という新しい制約が導入されました。これにより、例えばa[1 << 63]
のようなインデックスがコンパイル時に不正と判断されるようになります。
- 配列、スライス、文字列のインデックスに関するルールが整理され、特に定数インデックスに対して「非負であり、
-
スライス式(スライシング):
a[low:high]
のようなスライス式における定数インデックスlow
およびhigh
についても、「非負であり、int
型の値で表現可能でなければならない」という制約が追加されました。
-
make
関数:make
関数に渡されるサイズ引数(スライスの長さや容量、チャネルのバッファサイズなど)についても、「非負であり、int
型の値で表現可能でなければならない」という制約が追加されました。- この変更を具体的に示すために、
s := make([]int, 1<<63)
という例が追加されました。この例は、「不正:len(s)
はint
型の値で表現できない」とコメントされており、1 << 63
がint
の範囲外であるためコンパイルエラーとなることを示しています。1 << 63
は2^63
であり、これは符号付き64ビット整数(int64
)の最大値2^63 - 1
を超えるか、あるいは符号付き32ビット整数(int32
)では遥かに大きすぎる値です。Goのint
は符号付きであるため、この値は通常int
の範囲外となります。
これらの変更は、Goコンパイラが定数式を評価する際に、最終的に int
型に収まることを保証するためのものです。これにより、コンパイル時に検出できるエラーが増え、実行時の予期せぬパニックやメモリ関連の問題を防ぐことができます。
コアとなるコードの変更箇所
変更は doc/go_spec.html
ファイルに対して行われています。これはGo言語の公式仕様書であり、Goコンパイラの挙動を定義する文書です。
具体的には、以下のセクションが修正されています。
- 配列型 (Array types): 配列の長さに関する記述。
- インデックス式 (Index expressions): 配列、スライス、文字列のインデックスに関する記述。特に、非マップ型に対する一般的なインデックスルールが追加されています。
- スライス式 (Slice expressions): スライシング操作におけるインデックスに関する記述。
- 組み込み関数
make
:make
関数に渡されるサイズ引数に関する記述。
これらの変更は、既存のテキストを修正または削除し、新しいテキストを追加することで行われています。特に、int
型への適合性に関する文言が繰り返し追加されています。
コアとなるコードの解説
変更されたHTMLドキュメントの抜粋と解説です。
-
配列の長さに関する変更:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -815,12 +815,13 @@ ElementType = Type . </pre> <p> -The length is part of the array's type and must be a -<a href="#Constant_expressions">constant expression</a> that evaluates to a non-negative -integer value. The length of array <code>a</code> can be discovered +The length is part of the array's type; it must evaluate to a non- +negative <a href="#Constants">constant</a> representable by a value +of type <code>int</code>. +The length of array <code>a</code> can be discovered using the built-in function <a href="#Length_and_capacity"><code>len</code></a>. The elements can be addressed by integer <a href="#Index_expressions">indices</a> -indices 0 through <code>len(a)-1</code>. +0 through <code>len(a)-1</code>. Array types are always one-dimensional but may be composed to form multi-dimensional types. </p>
- 変更点: 配列の長さが「非負の整数値に評価される定数式」であることに加え、「
int
型の値で表現可能な非負の定数」でなければならないと明確化されました。これは、配列の長さがint
の範囲に収まることを保証します。
- 変更点: 配列の長さが「非負の整数値に評価される定数式」であることに加え、「
-
インデックス式に関する変更:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -2497,13 +2498,21 @@ The value <code>x</code> is called the rules apply:\n </p>\n \n+<p>\n+If <code>a</code> is not a map:\n+</p>\n+<ul>\n+\t<li>the index <code>x</code> must be an integer value; it is <i>in range</i> if <code>0 <= x < len(a)</code>,\n+\t otherwise it is <i>out of range</i></li>\n+\t<li>a <a href="#Constants">constant</a> index must be non-negative\n+\t and representable by a value of type <code>int</code>\n+</ul>\n+\n <p>\n For <code>a</code> of type <code>A</code> or <code>*A</code>\n where <code>A</code> is an <a href="#Array_types">array type</a>:\n </p>\n <ul>\n-\t<li><code>x</code> must be an integer value; it is <i>in range</i> if <code>0 <= x < len(a)</code>,\n-\t otherwise it is <i>out of range</i></li>\n \t<li>a <a href="#Constants">constant</a> index must be in range</li>\n \t<li>if <code>a</code> is <code>nil</code> or if <code>x</code> is out of range at run time,\n \t a <a href="#Run_time_panics">run-time panic</a> occurs</li>
- 変更点: マップではない型(配列、スライス、文字列など)に対する一般的なインデックスルールが追加されました。特に、定数インデックスは「非負であり、
int
型の値で表現可能でなければならない」と明記されました。これにより、以前は各型に散らばっていたインデックスの制約が整理され、一貫性が向上しました。
- 変更点: マップではない型(配列、スライス、文字列など)に対する一般的なインデックスルールが追加されました。特に、定数インデックスは「非負であり、
-
make
関数に関する変更:--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -4985,8 +4991,9 @@ make(T, n) channel asynchronous channel of type T, buffer size n\n \n <p>\n The size arguments <code>n</code> and <code>m</code> must be integer values.\n-A <a href="#Constants">constant</a> size argument must not be negative, and\n-if both <code>n</code> and <code>m</code> are provided and are constant, then\n+A <a href="#Constants">constant</a> size argument must be non-negative and\n+representable by a value of type <code>int</code>.\n+If both <code>n</code> and <code>m</code> are provided and are constant, then\n <code>n</code> must be no larger than <code>m</code>.\n If <code>n</code> is negative or larger than <code>m</code> at run time,\n a <a href="#Run_time_panics">run-time panic</a> occurs.\n@@ -4995,6 +5002,7 @@ a <a href="#Run_time_panics">run-time panic</a> occurs.\n <pre>\n s := make([]int, 10, 100) // slice with len(s) == 10, cap(s) == 100\n s := make([]int, 1e3) // slice with len(s) == cap(s) == 1000\n+s := make([]int, 1<<63) // illegal: len(s) is not representable by a value of type int\n s := make([]int, 10, 0)\t // illegal: len(s) > cap(s)\n c := make(chan int, 10) // channel with a buffer size of 10\n m := make(map[string]int, 100) // map with initial space for 100 elements\n ``` * **変更点**: `make` 関数のサイズ引数も「非負であり、`int` 型の値で表現可能でなければならない」という制約が追加されました。 * **重要な例**: `s := make([]int, 1<<63)` が不正な例として追加されました。これは、`1<<63` (2の63乗) が `int` 型で表現できる範囲を超えているため、コンパイルエラーとなることを示しています。この例は、この仕様変更の具体的な影響を非常に明確に示しています。
これらの変更は、Go言語の型システムと定数評価の厳密性を高め、異なる環境での予測可能な挙動を保証するために不可欠です。
関連リンク
- Go Language Specification: https://go.dev/ref/spec (このコミットが修正したドキュメントの最新版)
- Go Issue Tracker: https://go.dev/issue (関連する議論やバグ報告が見つかる可能性)
参考にした情報源リンク
- Go Language Specification (コミット対象のドキュメント):
doc/go_spec.html
の変更履歴 - Goの
int
型に関するドキュメント: https://go.dev/ref/spec#Numeric_types - Goの定数に関するドキュメント: https://go.dev/ref/spec#Constants
- Goの配列、スライス、
make
関数に関するドキュメント: https://go.dev/ref/spec#Array_types, https://go.dev/ref/spec#Slice_types, https://go.dev/ref/spec#Making_slices_maps_and_channels - Goのコードレビューシステム (Gerrit): https://golang.org/cl/6903048 (コミットメッセージに記載されている変更リストへのリンク)