配列、スライス(と文字列):'append'の動作原理 (Arrays, slices (and strings): The mechanics of 'append')
配列、スライス(と文字列):‘append’の動作原理 #
Arrays, slices (and strings): The mechanics of ‘append’ By Rob Pike
はじめに #
手続き型プログラミング言語において共通した機能のひとつに配列という概念があります。配列は単純に見えて、言語に追加する際には 答えなければならない多くの設問にこたえなければいけません。たとえば次のようなものです。
- 固定長なのか、可変長なのか
- 長さは型に含めるのか
- 多次元配列はどのように表現するか
- 空の配列が何を意味するか
これらの設問に対する回答が、配列が単に言語の一機能になるか、それとも言語設計の中心になるかをわけます。
Goの開発の初期段階で、言語設計がしっくりくるまで、これらの設問に対する答えを決めるのに1年かかりました。 鍵となったのはスライスの導入でした。スライスによって、固定長の配列に柔軟性や拡張性をもったデータ構造を与えました。 しかしながら、今日まで、Goを使い始めたばかりのプログラマはスライスの動作の理解にしばしばつまづいています。 おそらくそれは他の言語での経験がスライスに対する考え方に影響しているからでしょう。
この記事では、その混乱を解決しようと思います。そのために、ひとつひとつ部品を積み重ねて、組み込み関数の append がどのように動作するか、
そしてなぜそのように動作するのかを説明します。
配列 #
Goにおいて、配列は重要な要素ですが、工事における基礎のように、配列はより見えやすい構成要素の下に隠されています。 より面白くて、強力で、輝くアイデアであるスライスの話をする前に、まずは簡単に配列の説明をしましょう。
配列はGoのプログラム内にはあまり見られません。なぜなら配列の大きさは型の一部で、それによって表現力が制限されるからです。
次の宣言では
var buffer [256]byte
は変数バッファを宣言しています。このバッファは256バイトを保持します。 buffer は型その大きさをを型情報に含んでいて
[256]byte となっています。512バイトの配列は、その専用の型である [512]byte 型となります。
配列に紐付いたデータは、たった一つ、配列の要素だけです。構文の観点でいえば、さきほどの buffer はメモリ上では次のようになっています。
buffer: byte byte byte ... 256 times ... byte byte byte
つまり、変数は256バイトのデータを保持していて、ただそれだけです。私たちは各要素によく知られたインデックスの構文でアクセスできます。
buffer[0] 、 buffer[1] から始まって buffer[255] までです。(0から255までインデックスの範囲で256の要素をカバーしています)
この範囲の外側にある値のインデックスにアクセスしようとすると、プログラムがクラッシュします。
len という名前の組み込み関数があり、これは配列、スライス、また他のいくつかのデータ型の要素数を返します。
配列においては、 len が何を返すかは明らかです。私たちの例では len(buffer) は固定値の 256 を返します。
配列には使われるべき場所があります。インスタンスの変換行列として良い表現になっています。しかし、Goで配列がもっともよく使われるのは、 スライス内部で保存領域を確保する目的で使われるときです。
...