Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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 となっていました。

この挙動は多くの場合で問題ありませんが、特定のシナリオでは、スライスの容量をより細かく制御したいというニーズがありました。例えば、以下のようなケースが考えられます。

  1. メモリの事前割り当てと再利用: スライスを操作する際に、将来的に要素が追加されることが分かっている場合、事前に適切な容量を持つスライスを作成することで、不要な再割り当て(reallocation)を防ぎ、パフォーマンスを向上させることができます。
  2. バッファの効率的な管理: ネットワーク通信やファイルI/Oなど、固定サイズのバッファをスライスとして扱う場合、バッファの全体容量を明示的に指定できると、より安全で効率的なコードが書けます。
  3. スライスを返す関数の設計: 関数がスライスを返す際に、呼び出し元がそのスライスの基底配列のどこまでアクセスできるかを制御したい場合があります。例えば、内部バッファの一部を公開しつつ、そのバッファ全体へのアクセスは制限したいといった状況です。

このような背景から、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
  • 要素: ta[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 ファイルのみを変更しています。

具体的には、以下の部分が変更されています。

  1. ファイルのメタデータ更新:

    --- 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"
     }-->
    

    仕様書のバージョン日付が更新されています。

  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] に対応します。

  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 &lt;= low &lt;= high &lt;= max &lt;= 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: スライスの一般的な落とし穴と、それらを避けるためのヒントが提供されています。

参考にした情報源リンク

このコミットは、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 となっていました。

この挙動は多くの場合で問題ありませんが、特定のシナリオでは、スライスの容量をより細かく制御したいというニーズがありました。例えば、以下のようなケースが考えられます。

  1. メモリの事前割り当てと再利用: スライスを操作する際に、将来的に要素が追加されることが分かっている場合、事前に適切な容量を持つスライスを作成することで、不要な再割り当て(reallocation)を防ぎ、パフォーマンスを向上させることができます。これは、特に大量のデータを扱う場合や、パフォーマンスがクリティカルなアプリケーションにおいて重要です。例えば、ネットワークからデータを読み込むバッファを扱う際に、バッファの全体容量をスライスに反映させつつ、実際に読み込んだデータ部分のみを長さとして表現したい場合に有効です。
  2. バッファの効率的な管理: ネットワーク通信やファイルI/Oなど、固定サイズのバッファをスライスとして扱う場合、バッファの全体容量を明示的に指定できると、より安全で効率的なコードが書けます。これにより、基底配列の範囲を超えたアクセスを防ぎつつ、利用可能な最大容量を明確にできます。
  3. スライスを返す関数の設計: 関数がスライスを返す際に、呼び出し元がそのスライスの基底配列のどこまでアクセスできるかを制御したい場合があります。例えば、内部バッファの一部を公開しつつ、そのバッファ全体へのアクセスは制限したいといった状況です。これにより、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ランタイムの安全機構です。例えば、maxcap(a) を超える場合や、highmax を超える場合などにパニックが発生します。

具体例

コミットメッセージ内の例を再掲します。

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
  • 要素: ta[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ドキュメントです。

具体的には、以下の部分が変更されています。

  1. ファイルのメタデータ更新:

    --- 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のリリースサイクルの一部として行われたことを示唆しています。

  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つのインデックスを持つ形式を導入しています。| は「または」を意味し、どちらかの形式が有効であることを示します。

  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 &lt;= low &lt;= high &lt;= max &lt;= 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のリリースノートには、このフルスライス式を含む新機能の概要が記載されています。

参考にした情報源リンク