[インデックス 15482] ファイルの概要
このコミットは、Go言語の組み込み関数である append
のドキュメントに、バイトスライスに文字列を追記する特殊なケースに関する記述を追加するものです。具体的には、[]byte
型のスライスに文字列を append
する際の挙動が明示的に示されています。
コミット
commit f12796e9f7233266163d4003b528dd099b0f1799
Author: Rob Pike <r@golang.org>
Date: Wed Feb 27 16:11:17 2013 -0800
builtin: document appending a string to a byte slice
Fixes #4873.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7421043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f12796e9f7233266163d4003b528dd099b0f1799
元コミット内容
このコミットは、Go言語の組み込み関数 append
のドキュメントに、バイトスライスに文字列を追記する際の特別なケースに関する説明を追加します。
具体的には、append([]byte("hello "), "world"...)
のように、バイトスライスに文字列を可変長引数として ...
を付けて渡すことで、文字列の内容をバイトスライスに追記できるという挙動が明記されました。
変更の背景
Go言語の append
関数は、スライスに要素を追加するための非常に汎用的な組み込み関数です。通常、append
は同じ型の要素またはスライスを既存のスライスに追加するために使用されます。しかし、Go言語の設計において、文字列 (string
) とバイトスライス ([]byte
) は密接に関連しており、特に文字列がUTF-8エンコードされたバイト列として内部的に扱われるため、両者間には特定の変換規則が存在します。
このコミットが行われた背景には、append
関数がバイトスライスに文字列を追記できるという、一見すると直感的ではないが非常に便利な「特殊なケース」が存在し、それが公式ドキュメントに明記されていなかったという状況があります。開発者がこの挙動を理解し、適切に利用できるようにするため、ドキュメントの明確化が求められました。
Fixes #4873
とあることから、この挙動に関する既存のバグ報告や機能要望(Issue 4873)が存在し、その解決策としてドキュメントの追加が選択されたと考えられます。これにより、開発者はこの機能の存在を知り、誤解なく利用できるようになります。
前提知識の解説
Go言語のスライス ([]Type
)
Go言語のスライスは、同じ型の要素の連続したシーケンスを参照するデータ構造です。スライスは配列の上に構築されており、長さ(len
)と容量(cap
)を持ちます。スライスは動的にサイズを変更できるかのように見えますが、実際には基になる配列の容量が許す範囲で拡張され、容量を超えると新しい基になる配列が割り当てられます。
Go言語の文字列 (string
)
Go言語の文字列は、不変のバイトスライスです。Goの文字列はUTF-8エンコードされたテキストを表すことが推奨されており、内部的にはバイトのシーケンスとして扱われます。文字列は直接変更することはできません。
append
組み込み関数
append
はGo言語の組み込み関数で、スライスに要素を追加するために使用されます。その基本的なシグネチャは以下の通りです。
func append(slice []Type, elems ...Type) []Type
slice
: 要素を追加する対象のスライス。elems ...Type
: スライスに追加する要素。可変長引数として渡されます。これは、個々の要素を列挙することも、別のスライスを...
を付けて展開して渡すことも可能です。
append
は新しいスライスを返します。これは、元のスライスの基になる配列に十分な容量がない場合、新しい配列が割り当てられ、要素がコピーされるためです。
文字列とバイトスライスの関係
Go言語では、文字列とバイトスライスは密接に関連しています。文字列は []byte
に型変換することができ、その逆も可能です。
[]byte("hello")
: 文字列 "hello" をバイトスライスに変換します。string([]byte{104, 101, 108, 108, 111})
: バイトスライスを文字列に変換します。
このコミットで言及されている「特殊なケース」は、append
関数が []byte
型のスライスに対して、string
型の引数を ...
を付けて受け入れることができるという点です。これは、Goコンパイラがこの特定のパターンを認識し、文字列をバイトスライスに変換してから append
操作を実行するためです。
技術的詳細
このコミットは、Go言語の仕様における append
関数の挙動、特に文字列とバイトスライスの間の暗黙的な変換に関する重要な側面を明確にしています。
Go言語の仕様では、append
関数の引数について厳密な型チェックが行われます。しかし、特定の状況下では、コンパイラが型変換を自動的に行うことがあります。このコミットで言及されているのは、まさにその一例です。
通常、append(slice []T, elems ...T)
の形式では、elems
の型は T
と一致する必要があります。しかし、slice
が []byte
型であり、elems
が string
型で ...
を伴う場合、Goコンパイラは string
を []byte
に変換してから append
操作を実行します。これは、文字列が本質的にバイトのシーケンスであるというGo言語の設計思想に基づいています。
この挙動は、Go言語の仕様書(The Go Programming Language Specification)の「Built-in functions」セクションにある append
関数の説明に、この特殊なケースが明示的に記載されることで、公式に認められたものとなります。このドキュメントの追加は、Go言語の設計者がこの特定のユースケースを意図的にサポートしており、それが言語の自然な一部であることを示しています。
この機能は、文字列をバイトスライスに効率的に結合したい場合に非常に便利です。例えば、ネットワークプロトコルの構築やファイルI/Oなど、バイト列を扱う場面で、文字列リテラルや既存の文字列を直接バイトスライスに追記できるため、冗長な型変換コードを記述する必要がなくなります。
コアとなるコードの変更箇所
変更は src/pkg/builtin/builtin.go
ファイルに対して行われました。
--- a/src/pkg/builtin/builtin.go
+++ b/src/pkg/builtin/builtin.go
@@ -114,6 +114,8 @@ type ComplexType complex64
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
+// As a special case, it is legal to append a string to a byte slice, like this:
+// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
// The copy built-in function copies elements from a source slice into a
具体的には、append
関数のドキュメントコメントに2行が追加されています。
コアとなるコードの解説
追加された2行は、append
関数の既存のドキュメントコメント内に挿入されています。
// As a special case, it is legal to append a string to a byte slice, like this:
// slice = append([]byte("hello "), "world"...)
-
// As a special case, it is legal to append a string to a byte slice, like this:
この行は、バイトスライスに文字列を追記することが「特殊なケース」として合法であることを明記しています。これは、通常のappend
の型規則からすると例外的な挙動であることを示唆しています。 -
// slice = append([]byte("hello "), "world"...)
この行は、具体的なコード例を提供しています。[]byte("hello ")
というバイトスライスに、文字列リテラル"world"
を...
を付けて追記する例です。この...
は、文字列"world"
が個々のバイト要素に展開されてappend
関数に渡されることを意味します。結果として、slice
には"hello world"
のバイト表現が格納されます。
この変更は、Go言語の組み込み関数のドキュメントをより完全で分かりやすいものにするためのものです。これにより、開発者は append
関数のこの特定の、しかし非常に便利な使用方法を公式に認識し、安心して利用できるようになります。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/f12796e9f7233266163d4003b528dd099b0f1799
- Gerrit Change-ID: https://golang.org/cl/7421043
参考にした情報源リンク
- Go Programming Language Specification - Built-in functions: https://go.dev/ref/spec#Built-in_functions (このコミットの後に更新された仕様書には、この特殊ケースが明記されています。)
- Go Slices: usage and internals: https://go.dev/blog/slices
- Go Strings, bytes, runes and characters: https://go.dev/blog/strings
- Go issue #4873 (元のIssueは直接見つかりませんでしたが、コミットメッセージに記載されているため、このドキュメント追加の背景にある問題を示唆しています。)
- (注: 検索結果ではGo言語のIssue #4873は直接特定できませんでしたが、コミットメッセージに記載されているため、このドキュメント追加の背景にある問題を示唆しています。)