[インデックス 11844] ファイルの概要
このコミットは、Go言語の公式仕様書 doc/go_spec.html
における文字列の記述を修正するものです。具体的には、文字列の振る舞いを「バイトの配列 (arrays of bytes)」ではなく「バイトのスライス (slices of bytes)」として説明するように変更しています。これは、Go言語における文字列の実際の挙動が、固定長の配列よりも動的なスライスに近いという認識に基づく、仕様書の記述の正確性を高めるための修正です。
コミット
commit 7bd6ebb104acb150263774d7fa054c1f93c67806
Author: Rob Pike <r@golang.org>
Date: Mon Feb 13 23:39:56 2012 +1100
spec: strings are more slices than arrays
Thanks to Aaron Kemp for noticing.
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5645097
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7bd6ebb104acb150263774d7fa054c1f93c67806
元コミット内容
spec: strings are more slices than arrays
Thanks to Aaron Kemp for noticing.
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5645097
変更の背景
この変更の背景には、Go言語における文字列の概念と、それが配列およびスライスというデータ構造とどのように関連しているかについての、より正確な表現を求める必要がありました。
Go言語の文字列は不変なバイトのシーケンスとして定義されています。初期の仕様書では、その振る舞いを「バイトの配列のようである」と記述していました。しかし、Go言語における「配列」は固定長であり、その長さは型の一部となります。一方、「スライス」は動的な長さを持ち、基となる配列の一部を参照するビューとして機能します。
文字列に対して行われる一般的な操作(インデックスアクセス、スライス操作 s[low:high]
など)は、固定長の配列の挙動よりも、動的なスライスの挙動に概念的に非常に近いです。例えば、文字列の一部を切り出す操作は、新しい文字列(元の文字列のサブシーケンス)を生成しますが、これはスライス操作と類似しています。また、文字列の長さは実行時に決定され、len()
関数で取得できますが、これは配列の固定長とは異なります。
Aaron Kemp氏からの指摘により、この記述の不正確さが認識され、Go言語の設計思想と実際の挙動により合致するよう、「配列」から「スライス」への修正が提案・適用されました。これにより、Go言語の仕様書がより正確で、開発者にとって誤解の少ないものとなることが意図されています。
前提知識の解説
Go言語における文字列 (string)
Go言語の string
型は、不変なバイトのシーケンスを表します。これは、一度文字列が作成されると、その内容を変更することはできないことを意味します。Goの文字列はUTF-8エンコードされたテキストを扱うように設計されており、len()
関数は文字列のバイト数を返します。個々の文字(ルーン)にアクセスするには、range
ループを使用するか、文字列をルーンのスライスに変換する必要があります。
Go言語における配列 (array)
Go言語の配列は、同じ型の要素の固定長のシーケンスです。配列の長さは型の一部であり、コンパイル時に決定されます。例えば、[5]int
と [10]int
は異なる型と見なされます。配列は値型であり、関数に渡される際にはコピーが作成されます。
Go言語におけるスライス (slice)
Go言語のスライスは、配列の上に構築された動的なデータ構造です。スライスは、基となる配列の一部を参照するビューとして機能します。スライスは長さと容量を持ち、append
関数などによって動的にサイズを変更できます(必要に応じて新しい基底配列が割り当てられます)。スライスは参照型であり、関数に渡される際には基底配列へのポインタ、長さ、容量が渡されます。
なぜ文字列が「スライス」に近いのか
文字列が「バイトのスライス」に似ているとされる主な理由は以下の通りです。
- 動的な長さ: 文字列の長さは固定ではなく、実行時に決定されます。これは固定長の配列よりも、動的な長さを特徴とするスライスに似ています。
- スライス操作: 文字列の一部を切り出す操作(例:
s[low:high]
)は、新しい文字列を生成します。この操作は、スライスから新しいスライスを作成する挙動と概念的に非常に似ています。 - インデックスアクセス: 文字列のインデックスアクセスはバイト単位で行われます。これは、スライスが基底配列の要素にインデックスでアクセスするのと同様です。
文字列自体は不変であるため、スライスのように要素を変更することはできませんが、その「振る舞い」や操作の概念は、配列よりもスライスに近しいとされています。
技術的詳細
このコミットの技術的詳細は、Go言語の仕様書における記述の正確性向上にあります。
Go言語の文字列は、内部的にはバイトのシーケンスとして表現されます。これは、C言語におけるchar*
のようなポインタと長さのペア、あるいはJavaのString
オブジェクトのような内部表現に似ています。重要なのは、Goの文字列が「不変」であるという特性です。一度作成された文字列の内容は変更できません。
変更前の仕様書では、この不変なバイトシーケンスとしての文字列の性質を「バイトの配列のように振る舞う」と説明していました。しかし、Go言語の配列は厳密には固定長であり、その長さは型情報の一部です。例えば、[10]byte
と[20]byte
は異なる型です。
一方、Go言語のスライスは、基底となる配列へのポインタ、長さ、容量を持つ構造体です。スライスは動的な長さを持ち、その長さは実行時に変化し得ます。文字列のlen()
関数がバイト数を返すこと、そして文字列に対してs[i]
のようなインデックスアクセスやs[low:high]
のようなスライス操作が可能であることは、その振る舞いが固定長の配列よりも、動的なスライスに酷似していることを示しています。
例えば、"hello"[1:4]
という文字列スライス操作は、新しい文字列"ell"
を生成します。これは、[]byte{104, 101, 108, 108, 111}[1:4]
というバイトスライス操作が[]byte{101, 108, 108}
という新しいバイトスライスを生成するのと概念的に同じです。文字列は不変であるため、スライスのように要素を直接変更することはできませんが、その「アクセス」や「部分取得」のメカニズムはスライス的です。
この修正は、Go言語の設計者たちが、言語の核となるデータ型である文字列の概念を、より正確かつ直感的に理解してもらうための努力の一環と見ることができます。特に、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\",
-\t\"Subtitle\": \"Version of February 13, 2012\"\
+\t\"Subtitle\": \"Version of February 14, 2012\"\
}-->
<!--
@@ -737,7 +737,7 @@ particular architecture.\
<p>
A <i>string type</i> represents the set of string values.\
-Strings behave like arrays of bytes but are immutable: once created,\
+Strings behave like slices of bytes but are immutable: once created,\
it is impossible to change the contents of a string.\
The predeclared string type is <code>string</code>.\
コアとなるコードの解説
このコミットにおける主要な変更は、doc/go_spec.html
ファイル内の以下の1行です。
-Strings behave like arrays of bytes but are immutable: once created,
+Strings behave like slices of bytes but are immutable: once created,
この変更は、Go言語の仕様書において、文字列の振る舞いを説明する際に使用される比喩を「バイトの配列 (arrays of bytes)」から「バイトのスライス (slices of bytes)」へと修正しています。
-
変更前:
Strings behave like arrays of bytes but are immutable:
- 文字列が「バイトの配列」のように振る舞うと記述されていました。これは、文字列がバイトのシーケンスであるという点では正しいですが、Goの配列が持つ「固定長」という厳密な意味合いとは異なります。文字列の長さは固定ではなく、実行時に決定されます。
-
変更後:
Strings behave like slices of bytes but are immutable:
- 文字列が「バイトのスライス」のように振る舞うと記述されるようになりました。Goのスライスは動的な長さを持ち、基底配列の一部を参照するビューです。文字列のインデックスアクセスやスライス操作(例:
s[low:high]
)は、スライスのそれと概念的に非常に似ています。この表現は、文字列の動的な性質と、その操作の振る舞いをより正確に反映しています。
- 文字列が「バイトのスライス」のように振る舞うと記述されるようになりました。Goのスライスは動的な長さを持ち、基底配列の一部を参照するビューです。文字列のインデックスアクセスやスライス操作(例:
この修正は、Go言語の文字列が不変であるという重要な特性は維持しつつ、その内部的な構造や操作の概念を、より適切なGoのデータ構造である「スライス」に例えることで、仕様書の記述の正確性と理解度を高めることを目的としています。
また、コミットの冒頭にある日付の変更 (Subtitle
の February 13, 2012
から February 14, 2012
へ) は、この仕様書が更新された日付を反映したものです。
関連リンク
- The Go Programming Language Specification - Go言語の公式仕様書
- Go Slices: usage and internals - Goブログのスライスに関する記事
- Go strings, bytes, runes and characters - Goブログの文字列に関する記事
参考にした情報源リンク
- Go言語の公式ドキュメントおよびブログ記事
- Go言語のソースコード(
doc/go_spec.html
) - Go言語における配列、スライス、文字列に関する一般的な知識