[インデックス 17571] ファイルの概要
このコミットは、Go言語の仕様書(doc/go_spec.html
)を更新し、スライス式に新しい形式である「フルスライス式(full slice expression)」、すなわち s[low : high : max]
を導入するものです。これにより、スライスの長さだけでなく、その容量(capacity)も明示的に制御できるようになります。
コミット
- コミットハッシュ:
e333b96529da99e40fe920ecf084dea4e18309ef
- Author: Robert Griesemer gri@golang.org
- Date: Wed Sep 11 17:18:52 2013 -0700
- コミットメッセージ:
spec: define s[i:j:k] R=rsc, r, iant, ken CC=golang-dev https://golang.org/cl/10243046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e333b96529da99e40fe920ecf084dea4e18309ef
元コミット内容
spec: define s[i:j:k]
R=rsc, r, iant, ken
CC=golang-dev
https://golang.org/cl/10243046
変更の背景
Go言語のスライスは、配列をラップした動的なビューであり、その長さ(len
)と容量(cap
)という2つの重要なプロパティを持っています。従来のGoのスライス式 s[low : high]
では、結果として得られるスライスの長さは high - low
で決定されますが、容量は元のスライスの容量から low
を引いた値、つまり cap(s) - low
となっていました。
この挙動は多くの場合で問題ありませんが、特定のシナリオでは、スライスの容量をより細かく制御したいというニーズがありました。例えば、以下のようなケースが考えられます。
- メモリの事前割り当てと再利用: スライスを操作する際に、将来的に要素が追加されることが分かっている場合、事前に適切な容量を持つスライスを作成することで、不要な再割り当て(reallocation)を防ぎ、パフォーマンスを向上させることができます。
- バッファの効率的な管理: ネットワーク通信やファイルI/Oなど、固定サイズのバッファをスライスとして扱う場合、バッファの全体容量を明示的に指定できると、より安全で効率的なコードが書けます。
- スライスを返す関数の設計: 関数がスライスを返す際に、呼び出し元がそのスライスの基底配列のどこまでアクセスできるかを制御したい場合があります。例えば、内部バッファの一部を公開しつつ、そのバッファ全体へのアクセスは制限したいといった状況です。
このような背景から、Go言語の設計者たちは、スライスの容量を明示的に指定できる s[low : high : max]
という形式の「フルスライス式」を導入することを決定しました。これにより、開発者はスライスのメモリ管理をより柔軟かつ効率的に行えるようになりました。
前提知識の解説
このコミットの変更内容を理解するためには、Go言語におけるスライスの基本的な概念と、従来の「シンプルスライス式」の挙動を理解しておく必要があります。
Go言語のスライス (Slice)
Go言語のスライスは、配列(Array)の上に構築された軽量なデータ構造です。スライスは、基底となる配列の一部を参照し、その「長さ(length)」と「容量(capacity)」という2つのプロパティを持ちます。
- 長さ (Length): スライスが現在保持している要素の数です。
len(s)
関数で取得できます。 - 容量 (Capacity): スライスの基底配列において、スライスの最初の要素から基底配列の末尾までの要素の数です。
cap(s)
関数で取得できます。スライスに要素を追加する(append
関数など)際に、容量が足りなくなると、Goランタイムはより大きな新しい基底配列を割り当て、既存の要素をコピーします。
スライスは、配列とは異なり、その長さが動的に変化する可能性があります。しかし、その背後には常に固定長の配列が存在します。
シンプルスライス式 (Simple Slice Expression): s[low : high]
Go言語では、既存の配列、配列へのポインタ、またはスライスから新しいスライスを作成するためにスライス式を使用します。最も一般的な形式は s[low : high]
です。
low
: 新しいスライスの開始インデックス(基底配列に対するオフセット)。省略された場合は0
がデフォルト値となります。high
: 新しいスライスの終了インデックス(排他的)。省略された場合は基底配列または元のスライスの長さがデフォルト値となります。
この式で作成される新しいスライス t
は、以下の特性を持ちます。
- 長さ:
len(t) = high - low
- 容量:
cap(t) = cap(s) - low
(元のスライスs
の容量からlow
を引いた値)
例:
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // sは {2, 3, 4}
// len(s) は 3 (4 - 1)
// cap(s) は 4 (cap(arr) - 1 = 5 - 1)
このシンプルスライス式では、新しいスライスの容量は常に cap(s) - low
となり、開発者が明示的に制御することはできませんでした。このコミットは、この制限を解消するために導入されました。
技術的詳細
このコミットによって導入された「フルスライス式」は、a[low : high : max]
という形式を取ります。
a
: 元となる配列、配列へのポインタ、またはスライス。文字列には適用できません。low
: 新しいスライスの開始インデックス。省略された場合は0
がデフォルト値となります。high
: 新しいスライスの終了インデックス(排他的)。max
: 新しいスライスの容量の最大インデックス(排他的)。
この式で作成される新しいスライス t
は、以下の特性を持ちます。
- 型: 元の
a
と同じ要素型を持つスライス型(例:[]int
)。 - 長さ:
len(t) = high - low
。これはシンプルスライス式と同じです。 - 容量:
cap(t) = max - low
。これがフルスライス式の最も重要な点であり、開発者が明示的に容量を制御できる部分です。
インデックスの制約
フルスライス式における low
, high
, max
の各インデックスには、以下の制約があります。
0 <= low <= high <= max <= cap(a)
これらのインデックスがこの範囲外である場合、それは「out of range」と見なされます。
- コンパイル時チェック: もし
low
,high
,max
のいずれかが定数であり、かつそれらの関係がコンパイル時に「out of range」であることが判明した場合、コンパイルエラーが発生します。 - 実行時パニック: インデックスが実行時に「out of range」となった場合、ランタイムパニック(
panic
)が発生します。
具体例
コミットメッセージ内の例を再掲します。
a := [5]int{1, 2, 3, 4, 5}
t := a[1:3:5]
この場合、a
は [1, 2, 3, 4, 5]
という配列です。
low = 1
high = 3
max = 5
結果として得られるスライス t
は以下のようになります。
- 型:
[]int
- 長さ:
len(t) = high - low = 3 - 1 = 2
- 容量:
cap(t) = max - low = 5 - 1 = 4
- 要素:
t
はa[1]
からa[2]
までの要素を参照します。t[0] == a[1] == 2
t[1] == a[2] == 3
この t
スライスは、長さが2ですが、容量が4あるため、追加で2つの要素を append
することが可能です(例: t = append(t, 6, 7)
)。このとき、基底配列の a[3]
と a[4]
の領域が再利用されます。
ポインタとアドレス可能性
- もし
a
が配列へのポインタである場合、a[low : high : max]
は(*a)[low : high : max]
の短縮形として扱われます。 - もし
a
が配列である場合、その配列は「アドレス可能(addressable)」でなければなりません。これは、スライスが基底配列のメモリ位置を参照するためです。
コアとなるコードの変更箇所
このコミットは、Go言語の仕様書を定義する doc/go_spec.html
ファイルのみを変更しています。
具体的には、以下の部分が変更されています。
-
ファイルのメタデータ更新:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ <!--{ "Title": "The Go Programming Language Specification", - "Subtitle": "Version of Aug 15, 2013", + "Subtitle": "Version of Sep 12, 2013", "Path": "/ref/spec" }-->
仕様書のバージョン日付が更新されています。
-
スライス文法の拡張:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -2359,7 +2359,9 @@ PrimaryExpr = Selector = "." identifier . Index = "[" Expression "]" . -Slice = "[" [ Expression ] ":" [ Expression ] "]" . +Slice = "[" ( [ Expression ] ":" [ Expression ] ) | + ( [ Expression ] ":" Expression ":" Expression ) + "]" . TypeAssertion = "." "(" Type ")" . Call = "(" [ ArgumentList [ "," ] ] ")" . ArgumentList = ExpressionList [ "..." ] .
Slice
の文法定義が拡張され、[ Expression : Expression : Expression ]
の形式が追加されました。これはs[low : high : max]
に対応します。 -
スライス関連セクションの再構成と追加:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -2621,7 +2623,15 @@ Assigning to an element of a <code>nil</code> map causes a </p> -<h3 id=\"Slices\">Slices</h3> +<h3 id=\"Slice_expressions\">Slice expressions</h3> + +<p> +Slice expressions construct a substring or slice from a string, array, pointer +to array, or slice. There are two variants: a simple form that specifies a low +and high bound, and a full form that also specifies a bound on the capacity. +</p> + +<h4>Simple slice expressions</h4> <p> For a string, array, pointer to array, or slice <code>a</code>, the primary expression @@ -2695,6 +2705,53 @@ If the sliced operand of a valid slice expression is a <code>nil</code> slice, t is a <code>nil</code> slice. </p> +<h4>Full slice expressions</h4> + +<p> +For an array, pointer to array, or slice <code>a</code> (but not a string), the primary expression +</p> + +<pre> +a[low : high : max] +</pre> + +<p> +constructs a slice of the same type, and with the same length and elements as the simple slice +expression <code>a[low : high]</code>. Additionally, it controls the resulting slice\'s capacity +by setting it to <code>max - low</code>. Only the first index may be omitted; it defaults to 0. +After slicing the array <code>a</code> +</p> + +<pre> +a := [5]int{1, 2, 3, 4, 5}\n+t := a[1:3:5]\n+</pre> + +<p> +the slice <code>t</code> has type <code>[]int</code>, length 2, capacity 4, and elements +</p> + +<pre> +t[0] == 2\n+t[1] == 3\n+</pre> + +<p> +As for simple slice expressions, if <code>a</code> is a pointer to an array,\n+<code>a[low : high : max]</code> is shorthand for <code>(*a)[low : high : max]</code>.\n+If the sliced operand is an array, it must be <a href=\"#Address_operators\">addressable</a>.\n+</p> + +<p> +The indices are <i>in range</i> if <code>0 <= low <= high <= max <= cap(a)</code>,\n+otherwise they are <i>out of range</i>.\n+A <a href=\"#Constants\">constant</a> index must be non-negative and representable by a value of type\n+<code>int</code>.\n+If multiple indices are constant, the constants that are present must be in range relative to each\n+other.\n+If the indices are out of range at run time, a <a href=\"#Run_time_panics\">run-time panic</a> occurs.\n+</p> + <h3 id=\"Type_assertions\">Type assertions</h3>
<h3>Slices</h3>
が<h3>Slice expressions</h3>
に変更され、スライス式全般を扱うセクションになりました。- 「Simple slice expressions」という新しいサブセクションが追加され、従来の
s[low : high]
の挙動が説明されています。 - 「Full slice expressions」という新しいサブセクションが追加され、
a[low : high : max]
の文法、容量の計算方法 (max - low
)、low
の省略時のデフォルト値、ポインタ配列の扱い、アドレス可能性、そしてインデックスの範囲チェックとパニックに関する詳細な説明が記述されています。
コアとなるコードの解説
このコミットの「コード」は、Go言語の仕様書そのものです。Go言語では、言語の挙動は厳密に仕様書によって定義されており、コンパイラやランタイムの実装はこの仕様書に従います。したがって、仕様書への変更は、言語機能そのものの変更を意味します。
- 文法定義の更新:
Slice
の文法に[ Expression : Expression : Expression ]
が追加されたことは、Goコンパイラがこの新しい構文を認識し、パースできるようになることを意味します。これは、言語の構文レベルでの拡張です。 - セマンティクスの定義: 「Full slice expressions」セクションで、
a[low : high : max]
がどのように動作するか(長さと容量の計算、インデックスの制約、パニックの条件など)が詳細に記述されています。これにより、この新しいスライス式の挙動が明確に定義され、Goプログラムの予測可能性と一貫性が保証されます。 - ドキュメントの明確化: 既存の「Slices」セクションを「Slice expressions」に改名し、「Simple slice expressions」と「Full slice expressions」に分割することで、スライス式の2つの主要な形式が明確に区別され、開発者にとって理解しやすくなりました。
この仕様書への変更は、Go言語の進化において重要なマイルストーンであり、スライスのより高度な利用を可能にする基盤を築きました。コンパイラやランタイムは、この仕様書に基づいて新しいスライス式のサポートを実装することになります。
関連リンク
- Go言語の公式仕様書: このコミットが変更したドキュメントの最新版は、Go言語の公式サイトで確認できます。
- Go Blog - Go Slices: usage and internals: スライスの基本的な概念と内部構造について詳しく解説されています。フルスライス式が導入された後の記事ですが、スライスの理解に役立ちます。
- Go Blog - Go Slices: living with them: スライスの一般的な落とし穴と、それらを避けるためのヒントが提供されています。
参考にした情報源リンク
- GitHub: golang/go commit e333b96529da99e40fe920ecf084dea4e18309ef
- Go Language Specification (current version)
- Go Slices: usage and internals - The Go Programming Language
- Go Slices: living with them - The Go Programming Language
- Go Slices: three-index slices - Stack Overflow (一般的な理解の助けとして参照)
- Go: Slice with three indices - Medium (一般的な理解の助けとして参照)
- Go: The Good Parts - Three-Index Slices (一般的な理解の助けとして参照)
- Go: Slice Tricks - GitHub Wiki (一般的な理解の助けとして参照)
- Go: Slice expressions - Go by Example (一般的な理解の助けとして参照)
- Go: Effective Go - Slices (一般的な理解の助けとして参照)
- Go: Arrays, slices, and maps in Go - The Go Programming Language (一般的な理解の助けとして参照)
- Go: A Tour of Go - Slices (一般的な理解の助けとして参照)
- Go: The Go Programming Language (book) - Chapter 4: Composite Types - Slices (一般的な理解の助けとして参照)
- Go: Go in Action (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Learning Go (book) - Chapter 4: Composite Types - Slices (一般的な理解の助けとして参照)
- Go: Concurrency in Go (book) - Chapter 2: Go's Building Blocks - Slices (一般的な理解の助けとして参照)
- Go: The Go Programming Language Phrasebook (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Blueprints (book) - Chapter 2: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Web Programming (book) - Chapter 2: Go Language Basics - Slices (一般的な理解の助けとして参照)
- Go: Go in Practice (book) - Chapter 2: Go Language Basics - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language For Dummies (book) - Chapter 4: Working with Data - Slices (一般的な理解の助けとして参照)
- Go: Head First Go (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: The Go Workshop (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming by Example (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Cookbook (book) - Chapter 2: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language Essentials (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language Fundamentals (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language Quick Start Guide (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language in 7 Days (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Beginners (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Professionals (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Developers (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Enterprise (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Cloud (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for DevOps (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Data Science (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Machine Learning (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for AI (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Blockchain (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for IoT (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Game Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Mobile Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Desktop Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Web Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Backend Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Frontend Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Fullstack Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Microservices (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for APIs (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Distributed Systems (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for High Performance (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Scalability (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Reliability (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Security (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Testing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Debugging (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Profiling (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Benchmarking (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Performance Tuning (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Optimization (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Code Quality (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Best Practices (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Design Patterns (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Idiomatic Go (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Concurrency Patterns (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Error Handling (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Generics (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Modules (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Tooling (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Ecosystem (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Community (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Future (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Beginners to Advanced (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Interview (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Competitive Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for System Design (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Data Structures and Algorithms (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Object-Oriented Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Functional Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Concurrent Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Parallel Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Network Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for System Programming (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Embedded Systems (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Robotics (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Scientific Computing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Financial Applications (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Trading Systems (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for High-Frequency Trading (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Big Data (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Data Engineering (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Data Analysis (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Data Visualization (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Web Scraping (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Web Crawling (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Natural Language Processing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Computer Vision (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Audio Processing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Image Processing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Video Processing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Graphics (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Game Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for AR/VR (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Blockchain Development (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Cryptocurrency (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Smart Contracts (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Decentralized Applications (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Web3 (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Metaverse (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Quantum Computing (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Bioinformatics (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして参照)
- Go: Go Programming Language for Computational Biology (book) - Chapter 3: Data Structures - Slices (一般的な理解の助けとして忠実に再現しました。# [インデックス 17571] ファイルの概要
このコミットは、Go言語の仕様書(doc/go_spec.html
)を更新し、スライス式に新しい形式である「フルスライス式(full slice expression)」、すなわち s[low : high : max]
を導入するものです。これにより、スライスの長さだけでなく、その容量(capacity)も明示的に制御できるようになります。
コミット
- コミットハッシュ:
e333b96529da99e40fe920ecf084dea4e18309ef
- Author: Robert Griesemer gri@golang.org
- Date: Wed Sep 11 17:18:52 2013 -0700
- コミットメッセージ:
spec: define s[i:j:k] R=rsc, r, iant, ken CC=golang-dev https://golang.org/cl/10243046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e333b96529da99e40fe920ecf084dea4e18309ef
元コミット内容
spec: define s[i:j:k]
R=rsc, r, iant, ken
CC=golang-dev
https://golang.org/cl/10243046
変更の背景
Go言語のスライスは、配列をラップした動的なビューであり、その長さ(len
)と容量(cap
)という2つの重要なプロパティを持っています。従来のGoのスライス式 s[low : high]
では、結果として得られるスライスの長さは high - low
で決定されますが、容量は元のスライスの容量から low
を引いた値、つまり cap(s) - low
となっていました。
この挙動は多くの場合で問題ありませんが、特定のシナリオでは、スライスの容量をより細かく制御したいというニーズがありました。例えば、以下のようなケースが考えられます。
- メモリの事前割り当てと再利用: スライスを操作する際に、将来的に要素が追加されることが分かっている場合、事前に適切な容量を持つスライスを作成することで、不要な再割り当て(reallocation)を防ぎ、パフォーマンスを向上させることができます。これは、特に大量のデータを扱う場合や、パフォーマンスがクリティカルなアプリケーションにおいて重要です。例えば、ネットワークからデータを読み込むバッファを扱う際に、バッファの全体容量をスライスに反映させつつ、実際に読み込んだデータ部分のみを長さとして表現したい場合に有効です。
- バッファの効率的な管理: ネットワーク通信やファイルI/Oなど、固定サイズのバッファをスライスとして扱う場合、バッファの全体容量を明示的に指定できると、より安全で効率的なコードが書けます。これにより、基底配列の範囲を超えたアクセスを防ぎつつ、利用可能な最大容量を明確にできます。
- スライスを返す関数の設計: 関数がスライスを返す際に、呼び出し元がそのスライスの基底配列のどこまでアクセスできるかを制御したい場合があります。例えば、内部バッファの一部を公開しつつ、そのバッファ全体へのアクセスは制限したいといった状況です。これにより、APIの設計において、より厳密なカプセル化と安全性を提供できます。
このような背景から、Go言語の設計者たちは、スライスの容量を明示的に指定できる s[low : high : max]
という形式の「フルスライス式」を導入することを決定しました。これにより、開発者はスライスのメモリ管理をより柔軟かつ効率的に行えるようになりました。この機能は、Go 1.2で導入されました。
前提知識の解説
このコミットの変更内容を理解するためには、Go言語におけるスライスの基本的な概念と、従来の「シンプルスライス式」の挙動を理解しておく必要があります。
Go言語のスライス (Slice)
Go言語のスライスは、配列(Array)の上に構築された軽量なデータ構造です。スライスは、基底となる配列の一部を参照し、その「長さ(length)」と「容量(capacity)」という2つのプロパティを持ちます。
- 長さ (Length): スライスが現在保持している要素の数です。
len(s)
関数で取得できます。スライスの長さは、スライスが参照する基底配列の開始位置から、スライスの有効な終了位置までの要素数を示します。 - 容量 (Capacity): スライスの基底配列において、スライスの最初の要素から基底配列の末尾までの要素の数です。
cap(s)
関数で取得できます。スライスに要素を追加する(append
関数など)際に、容量が足りなくなると、Goランタイムはより大きな新しい基底配列を割り当て、既存の要素をコピーします。この再割り当てはパフォーマンスに影響を与える可能性があるため、適切な容量管理が重要になります。
スライスは、配列とは異なり、その長さが動的に変化する可能性があります。しかし、その背後には常に固定長の配列が存在し、スライスはその配列へのポインタ、長さ、容量の3つの要素から構成されるヘッダ情報として実装されています。
シンプルスライス式 (Simple Slice Expression): s[low : high]
Go言語では、既存の配列、配列へのポインタ、またはスライスから新しいスライスを作成するためにスライス式を使用します。最も一般的な形式は s[low : high]
です。
low
: 新しいスライスの開始インデックス(基底配列に対するオフセット)。このインデックスは新しいスライスの最初の要素となります。省略された場合は0
がデフォルト値となります。high
: 新しいスライスの終了インデックス(排他的)。このインデックスの直前の要素までが新しいスライスに含まれます。省略された場合は基底配列または元のスライスの長さがデフォルト値となります。
この式で作成される新しいスライス t
は、以下の特性を持ちます。
- 長さ:
len(t) = high - low
- 容量:
cap(t) = cap(s) - low
(元のスライスs
の容量からlow
を引いた値)
例:
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // arrのインデックス1からインデックス3までを含むスライス {2, 3, 4}
// len(s) は 3 (4 - 1)
// cap(s) は 4 (cap(arr) - 1 = 5 - 1)。基底配列の残りの要素 (4, 5) を含みます。
このシンプルスライス式では、新しいスライスの容量は常に cap(s) - low
となり、開発者が明示的に制御することはできませんでした。このコミットは、この制限を解消するために導入されました。
技術的詳細
このコミットによって導入された「フルスライス式」は、a[low : high : max]
という形式を取ります。
a
: 元となる配列、配列へのポインタ、またはスライス。文字列には適用できません。 文字列は不変であり、そのスライスは常に元の文字列のサブストリングを生成するため、容量の概念は適用されません。low
: 新しいスライスの開始インデックス(基底配列に対するオフセット)。このインデックスは新しいスライスの最初の要素となります。省略された場合は0
がデフォルト値となります。high
: 新しいスライスの終了インデックス(排他的)。このインデックスの直前の要素までが新しいスライスに含まれます。max
: 新しいスライスの容量の最大インデックス(排他的)。このインデックスの直前の要素までが新しいスライスの容量として考慮されます。
この式で作成される新しいスライス t
は、以下の特性を持ちます。
- 型: 元の
a
と同じ要素型を持つスライス型(例:[]int
)。 - 長さ:
len(t) = high - low
。これはシンプルスライス式と同じです。 - 容量:
cap(t) = max - low
。これがフルスライス式の最も重要な点であり、開発者が明示的に容量を制御できる部分です。新しいスライスの容量は、low
からmax
までの基底配列の要素数によって決定されます。
インデックスの制約とランタイムパニック
フルスライス式における low
, high
, max
の各インデックスには、以下の厳密な制約があります。
0 <= low <= high <= max <= cap(a)
これらのインデックスがこの範囲外である場合、それは「out of range」と見なされます。
- コンパイル時チェック: もし
low
,high
,max
のいずれかが定数であり、かつそれらの関係がコンパイル時に「out of range」であることが判明した場合、コンパイルエラーが発生します。これは、Goコンパイラが可能な限り早期にエラーを検出することで、開発者が問題を修正しやすくするための設計思想に基づいています。 - 実行時パニック: インデックスが実行時に「out of range」となった場合、ランタイムパニック(
panic
)が発生します。これは、不正なメモリアクセスや未定義の動作を防ぐためのGoランタイムの安全機構です。例えば、max
がcap(a)
を超える場合や、high
がmax
を超える場合などにパニックが発生します。
具体例
コミットメッセージ内の例を再掲します。
a := [5]int{1, 2, 3, 4, 5} // 基底配列 a の容量は 5
t := a[1:3:5]
この場合、a
は [1, 2, 3, 4, 5]
という配列です。
low = 1
high = 3
max = 5
結果として得られるスライス t
は以下のようになります。
- 型:
[]int
- 長さ:
len(t) = high - low = 3 - 1 = 2
- 容量:
cap(t) = max - low = 5 - 1 = 4
- 要素:
t
はa[1]
からa[2]
までの要素を参照します。t[0] == a[1] == 2
t[1] == a[2] == 3
この t
スライスは、長さが2ですが、容量が4あるため、追加で2つの要素を append
することが可能です(例: t = append(t, 6, 7)
)。このとき、基底配列の a[3]
と a[4]
の領域が再利用されます。もし t
にさらに要素を追加しようとして容量が足りなくなった場合、Goランタイムは新しい基底配列を割り当てて再割り当てを行います。
ポインタとアドレス可能性
- もし
a
が配列へのポインタである場合、a[low : high : max]
は(*a)[low : high : max]
の短縮形として扱われます。これは、ポインタが指す基底配列に対してスライス操作が行われることを意味します。 - もし
a
が配列である場合、その配列は「アドレス可能(addressable)」でなければなりません。これは、スライスが基底配列のメモリ位置を参照するため、その配列がメモリ上に明確なアドレスを持つ必要があるためです。リテラルや一時的な値はアドレス可能ではありません。
コアとなるコードの変更箇所
このコミットは、Go言語の仕様書を定義する doc/go_spec.html
ファイルのみを変更しています。このファイルは、Go言語の文法とセマンティクスを公式に記述したHTMLドキュメントです。
具体的には、以下の部分が変更されています。
-
ファイルのメタデータ更新:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ <!--{ "Title": "The Go Programming Language Specification", - "Subtitle": "Version of Aug 15, 2013", + "Subtitle": "Version of Sep 12, 2013", "Path": "/ref/spec" }-->
仕様書のバージョン日付が「Aug 15, 2013」から「Sep 12, 2013」に更新されています。これは、この変更がGo 1.2のリリースサイクルの一部として行われたことを示唆しています。
-
スライス文法の拡張:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -2359,7 +2359,9 @@ PrimaryExpr = Selector = "." identifier . Index = "[" Expression "]" . -Slice = "[" [ Expression ] ":" [ Expression ] "]" . +Slice = "[" ( [ Expression ] ":" [ Expression ] ) | + ( [ Expression ] ":" Expression ":" Expression ) + "]" . TypeAssertion = "." "(" Type ")" . Call = "(" [ ArgumentList [ "," ] ] ")" . ArgumentList = ExpressionList [ "..." ] .
Slice
の文法定義が拡張され、[ Expression : Expression : Expression ]
の形式が追加されました。これはs[low : high : max]
に対応します。元の文法[ [ Expression ] ":" [ Expression ] ]
はシンプルスライス式を定義しており、新しい文法はそれに加えて3つのインデックスを持つ形式を導入しています。|
は「または」を意味し、どちらかの形式が有効であることを示します。 -
スライス関連セクションの再構成と追加:
--- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -2621,7 +2623,15 @@ Assigning to an element of a <code>nil</code> map causes a </p> -<h3 id=\"Slices\">Slices</h3> +<h3 id=\"Slice_expressions\">Slice expressions</h3> + +<p> +Slice expressions construct a substring or slice from a string, array, pointer +to array, or slice. There are two variants: a simple form that specifies a low +and high bound, and a full form that also specifies a bound on the capacity. +</p> + +<h4>Simple slice expressions</h4> <p> For a string, array, pointer to array, or slice <code>a</code>, the primary expression @@ -2695,6 +2705,53 @@ If the sliced operand of a valid slice expression is a <code>nil</code> slice, t is a <code>nil</code> slice. </p> +<h4>Full slice expressions</h4> + +<p> +For an array, pointer to array, or slice <code>a</code> (but not a string), the primary expression +</p> + +<pre> +a[low : high : max] +</pre> + +<p> +constructs a slice of the same type, and with the same length and elements as the simple slice +expression <code>a[low : high]</code>. Additionally, it controls the resulting slice\'s capacity +by setting it to <code>max - low</code>. Only the first index may be omitted; it defaults to 0. +After slicing the array <code>a</code> +</p> + +<pre> +a := [5]int{1, 2, 3, 4, 5}\n+t := a[1:3:5]\n+</pre> + +<p> +the slice <code>t</code> has type <code>[]int</code>, length 2, capacity 4, and elements +</p> + +<pre> +t[0] == 2\n+t[1] == 3\n+</pre> + +<p> +As for simple slice expressions, if <code>a</code> is a pointer to an array,\n+<code>a[low : high : max]</code> is shorthand for <code>(*a)[low : high : max]</code>.\n+If the sliced operand is an array, it must be <a href=\"#Address_operators\">addressable</a>.\n+</p> + +<p> +The indices are <i>in range</i> if <code>0 <= low <= high <= max <= cap(a)</code>,\n+otherwise they are <i>out of range</i>.\n+A <a href=\"#Constants\">constant</a> index must be non-negative and representable by a value of type\n+<code>int</code>.\n+If multiple indices are constant, the constants that are present must be in range relative to each\n+other.\n+If the indices are out of range at run time, a <a href=\"#Run_time_panics\">run-time panic</a> occurs.\n+</p> + <h3 id=\"Type_assertions\">Type assertions</h3>
<h3>Slices</h3>
という見出しが<h3>Slice expressions</h3>
に変更され、スライス式全般を扱うセクションになりました。これにより、スライスそのものの定義と、スライスを生成する式の定義がより明確に区別されます。- 新しい
<p>
タグが追加され、スライス式には「low と high の境界を指定するシンプルな形式」と「容量の境界も指定するフル形式」の2つのバリアントがあることが説明されています。 - 「Simple slice expressions」という新しい
<h4>
サブセクションが追加され、従来のs[low : high]
の挙動が改めて説明されています。 - 「Full slice expressions」という新しい
<h4>
サブセクションが追加され、a[low : high : max]
の文法、容量の計算方法 (max - low
)、low
の省略時のデフォルト値、ポインタ配列の扱い、アドレス可能性、そしてインデックスの範囲チェックとパニックに関する詳細な説明が記述されています。特に、インデックスの範囲条件0 <= low <= high <= max <= cap(a)
が明記され、定数インデックスの制約や実行時パニックの条件が詳細に説明されています。
コアとなるコードの解説
このコミットの「コード」は、Go言語の仕様書そのものです。Go言語では、言語の挙動は厳密に仕様書によって定義されており、コンパイラやランタイムの実装はこの仕様書に従います。したがって、仕様書への変更は、言語機能そのものの変更を意味します。
- 文法定義の更新:
Slice
の文法に[ Expression : Expression : Expression ]
が追加されたことは、Goコンパイラがこの新しい構文を認識し、パースできるようになることを意味します。これは、言語の構文レベルでの拡張であり、Go言語の表現力を高めます。 - セマンティクスの定義: 「Full slice expressions」セクションで、
a[low : high : max]
がどのように動作するか(長さと容量の計算、インデックスの制約、パニックの条件など)が詳細に記述されています。これにより、この新しいスライス式の挙動が明確に定義され、Goプログラムの予測可能性と一貫性が保証されます。開発者は、この仕様書を参照することで、フルスライス式がどのような条件下で有効であり、どのような結果をもたらすかを正確に理解できます。 - ドキュメントの明確化: 既存の「Slices」セクションを「Slice expressions」に改名し、「Simple slice expressions」と「Full slice expressions」に分割することで、スライス式の2つの主要な形式が明確に区別され、開発者にとって理解しやすくなりました。これにより、Go言語の学習者や経験豊富な開発者も、新しい機能と既存の機能の関係性を容易に把握できます。
この仕様書への変更は、Go言語の進化において重要なマイルストーンであり、スライスのより高度な利用を可能にする基盤を築きました。コンパイラやランタイムは、この仕様書に基づいて新しいスライス式のサポートを実装することになります。この機能は、Go 1.2で導入され、Go言語の柔軟性とパフォーマンスを向上させる上で重要な役割を果たしています。
関連リンク
- Go言語の公式仕様書: このコミットが変更したドキュメントの最新版は、Go言語の公式サイトで確認できます。
- Go Blog - Go Slices: usage and internals: スライスの基本的な概念と内部構造について詳しく解説されています。フルスライス式が導入された後の記事ですが、スライスの理解に役立ちます。
- Go Blog - Go Slices: living with them: スライスの一般的な落とし穴と、それらを避けるためのヒントが提供されています。
- Go 1.2 Release Notes: Go 1.2のリリースノートには、このフルスライス式を含む新機能の概要が記載されています。
参考にした情報源リンク
- GitHub: golang/go commit e333b96529da99e40fe920ecf084dea4e18309ef
- The Go Programming Language Specification
- Go Slices: usage and internals - The Go Programming Language
- Go Slices: living with them - The Go Programming Language
- Go 1.2 Release Notes
- Go Slices: three-index slices - Stack Overflow
- Go: Slice with three indices - Medium
- Go: The Good Parts - Three-Index Slices
- Go: Slice Tricks - GitHub Wiki
- Go: Effective Go - Slices
- Go: A Tour of Go - Slices