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

[インデックス 17275] ファイルの概要

このコミットは、Go 1.2 リリースノートのドキュメントファイル doc/go1.2.txt に、3インデックススライス(three-index slices)がGo 1.2に含まれることを追記するものです。具体的には、cmd/gc(Goコンパイラ)がこの機能に対応したことが明記されています。

コミット

commit de2cf5113b3860d487ab6b9638521c91785486b7
Author: Rob Pike <r@golang.org>
Date:   Fri Aug 16 10:30:31 2013 +1000

    doc/go1.2.txt: three-index slices are going into 1.2
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/12931044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/de2cf511b3860d487ab6b9638521c91785486b7

元コミット内容

doc/go1.2.txt: three-index slices are going into 1.2

このコミットメッセージは、Go 1.2のリリースノートに、3インデックススライスが導入されることを示す記述を追加したことを簡潔に示しています。

変更の背景

Go言語のスライスは、配列の一部を参照するための強力なデータ構造です。Go 1.0およびGo 1.1では、スライスは a[low : high] の形式で作成され、low から high-1 までの要素を含み、その容量(capacity)は元の配列の low から末尾までの長さによって決定されていました。

しかし、この2インデックススライスでは、新しいスライスの容量を明示的に制限する方法がありませんでした。これにより、元のスライスからサブスライスを作成し、そのサブスライスに append 操作を行った際に、意図せず元の配列の範囲外の要素を上書きしてしまう可能性がありました。特に、元の配列の容量を完全に引き継いでしまうため、メモリの再割り当てを期待するようなシナリオで予期せぬ動作を引き起こすことがありました。

この問題を解決し、スライスの容量をより細かく制御できるようにするために、3インデックススライス a[low : high : max] が提案され、Go 1.2で導入されることになりました。このコミットは、その導入を公式ドキュメントに反映させるためのものです。

前提知識の解説

Go言語のスライス

Go言語のスライスは、配列の上に構築された動的なビューです。スライスは以下の3つの要素で構成されます。

  1. ポインタ: スライスが参照する基底配列の開始要素へのポインタ。
  2. 長さ (Length): スライスに含まれる要素の数。len(s) で取得できます。
  3. 容量 (Capacity): スライスの基底配列の開始要素から、基底配列の末尾までの要素の数。cap(s) で取得できます。

スライスは、make([]T, length, capacity) または既存の配列やスライスから a[low : high] の形式で作成されます。

2インデックススライス a[low : high]

  • low: 新しいスライスの開始インデックス(含む)。
  • high: 新しいスライスの終了インデックス(含まない)。
  • 新しいスライスの長さは high - low です。
  • 新しいスライスの容量は、元のスライス(または配列)の low から末尾までの容量を引き継ぎます。つまり、cap(a) - low となります。

append 関数とスライスの再割り当て

Goの組み込み関数 append は、スライスに要素を追加するために使用されます。

  • スライスの容量が十分な場合、append は既存の基底配列に要素を追加し、新しいスライスヘッダを返します。
  • スライスの容量が不足する場合、append はより大きな新しい基底配列を割り当て、既存の要素をコピーし、新しい要素を追加します。このとき、元のスライスとは異なる基底配列を参照する新しいスライスが返されます。

cmd/gc

cmd/gc は、Go言語の公式コンパイラです。Goのソースコードを機械語に変換する役割を担っています。新しい言語機能が導入される際には、このコンパイラがその機能を正しく解釈し、コンパイルできるように更新される必要があります。

技術的詳細

このコミットが参照している CL 10743046 は、Goコンパイラ cmd/gc に3インデックススライスを実装した変更リストです。

3インデックススライス a[low : high : max]

Go 1.2で導入された3インデックススライスは、スライスの作成時にその容量を明示的に制限する機能を提供します。

  • low: 新しいスライスの開始インデックス(含む)。
  • high: 新しいスライスの終了インデックス(含まない)。
  • max: 新しいスライスの容量の最大値を示すインデックス(含まない)。

この形式で作成されたスライス s := a[low : high : max] は、以下の特性を持ちます。

  • 長さ (Length): high - low
  • 容量 (Capacity): max - low

ここで、以下の条件が満たされる必要があります。 0 <= low <= high <= max <= cap(a)

3インデックススライスの利点

  1. 容量の制限: 新しいスライスの容量を、元のスライスの容量の一部に制限できます。これにより、append 操作が意図せず元の配列の他の部分を上書きするのを防ぐことができます。
  2. メモリ効率: 特定のユースケースにおいて、不要なメモリ割り当てを避けることができます。例えば、大きなバッファの一部を処理する際に、その部分だけをスライスとして渡し、そのスライスが元のバッファ全体にアクセスできないように制限できます。
  3. 安全性と予測可能性: append 操作が新しい基底配列を割り当てるタイミングをより予測しやすくなります。新しいスライスの容量を超えて要素を追加しようとすると、必ず新しい基底配列が割り当てられるため、元のデータへの意図しない変更を防ぎます。

具体例

package main

import "fmt"

func main() {
	// 元の配列
	arr := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

	// 2インデックススライス
	s1 := arr[2:5] // len=3, cap=8 (arr[2]からarrの末尾まで)
	fmt.Printf("s1: %v, len: %d, cap: %d\n", s1, len(s1), cap(s1)) // s1: [2 3 4], len: 3, cap: 8

	// s1に要素を追加すると、元の配列の5番目以降が変更される可能性がある
	s1 = append(s1, 100) // s1: [2 3 4 100]
	fmt.Printf("s1 after append: %v, len: %d, cap: %d\n", s1, len(s1), cap(s1))
	fmt.Printf("arr after s1 append: %v\n", arr) // arr: [0 1 2 3 4 100 6 7 8 9] (arr[5]が変更された)

	fmt.Println("---")

	// 3インデックススライス
	s2 := arr[2:5:5] // len=3, cap=3 (arr[2]からarr[4]までが容量)
	fmt.Printf("s2: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2)) // s2: [2 3 4], len: 3, cap: 3

	// s2に要素を追加すると、容量が不足するため新しい基底配列が割り当てられる
	s2 = append(s2, 200) // s2: [2 3 4 200]
	fmt.Printf("s2 after append: %v, len: %d, cap: %d\n", s2, len(s2), cap(s2))
	fmt.Printf("arr after s2 append: %v\n", arr) // arr: [0 1 2 3 4 100 6 7 8 9] (arrは変更されない)
}

この例からわかるように、3インデックススライスを使用することで、append 操作が元の基底配列に影響を与えることを防ぎ、より安全なコードを書くことができます。

コアとなるコードの変更箇所

--- a/doc/go1.2.txt
+++ b/doc/go1.2.txt
@@ -17,6 +17,7 @@ net: improve windows performance by up to 30% (CL 8670044).
 cmd/5a: removed support for R9/R10 (use m/g instead) (CL 9840043).
 cmd/5l: add MOVBS, MOVHS etc for sub-word moves (CL 12682043).
 cmd/cgo, cmd/go: support including C++ code with cgo (CL 8248043).
+cmd/gc: three-index slicing to set cap as well as length (CL 10743046).
 cmd/gc: make missing package error fatal (CL 12677043).
 cmd/go: test coverage (CL 10413044).
 cmd/go: add -t flag to 'go get' to download test dependencies (CL 12566046).

コアとなるコードの解説

このコミットは、doc/go1.2.txt ファイルに1行追加するだけの非常にシンプルな変更です。

追加された行は以下の通りです。 cmd/gc: three-index slicing to set cap as well as length (CL 10743046).

この行は、Go 1.2のリリースノートにおいて、Goコンパイラ (cmd/gc) が「長さだけでなく容量も設定するための3インデックススライス」をサポートしたことを明記しています。括弧内の CL 10743046 は、この機能の実装に関連する変更リスト(Change List)のIDを示しており、このIDを追跡することで、実際のコンパイラ側の変更内容を詳細に確認することができます。

この変更自体は機能の実装ではなく、その機能がGo 1.2に含まれることを公式に文書化するものです。これは、Go言語のリリースプロセスにおいて、新機能が導入される際に、その機能がどのバージョンで利用可能になるかをユーザーに明確に伝えるための重要なステップです。

関連リンク

  • Go 1.2 Release Notes (公式ドキュメント): このコミットが変更しているファイルが最終的に反映される場所です。
  • Go Slices: usage and internals (Go公式ブログ): スライスの基本的な概念と内部構造について詳しく解説されています。

参考にした情報源リンク