スライス

スライスは任意の型Tに対する型T[]のオブジェクトです。 スライスはTの配列の部分集合のビューを提供するか、 単に配列全体を指します。 スライスと動的配列は同じものです。

スライスは2つのメンバから構成されています。 - 最初の要素へのポインタとスライスの長さです:

T* ptr;
size_t length; // 32bit環境なら符号なし32ビット、64bit環境なら符号なし64ビット

新しい割り当てによりスライスを得る

新しい動的配列が作成されるとき、新しく割り当てられたメモリからのスライスが返されます:

auto arr = new int[5];
assert(arr.length == 5); // メモリはarr.ptrから参照される

この場合割り当てられたメモリは完全にガベージコレクタによって管理されます。 返されるスライスは根底にある要素の「ビュー」として振る舞います。

既存のメモリからスライスを得る

スライシング演算子を使いすでに存在するメモリと同じ所を指すスライスを得ることもできます。 スライシング演算子は別のスライス、静的配列、opSliceが実装されている構造体/クラスや その他いくつかのエンティティに適用できます。

例として式origin[start .. end]の中のスライシング演算子はoriginstartからendまでのすべての要素のスライスを得るのに使われます:

auto newArr = arr[1 .. 4]; // インデックス4は含まれません
assert(newArr.length == 3);
newArr[0] = 10; // arr[1]の別名であるnewArr[0]を変更

そのようなスライスは既存のメモリの新しいビューを生成します。 それは新しいコピーを作りません。 メモリ、またはそのスライスされた部分への参照を持つスライスがもはや存在しないなら、 それはガベージコレクタによって開放されます。

スライスを使うと、(たとえばパーサのような)1つのメモリブロックのみを操作し、 本当に必要な場所のみをスライスするようなものにおいて非常に効率的なコードを書くことができます。 この方法なら、新しいメモリブロックを割り当てる必要はありません。

前のセクションで見たように、[$]式はarr.lengthの短縮形です。 そのためarr[$]はスライスの最後のひとつ先の要素をインデックスし、 したがって(境界チェックが無効化されていなければ)RangeErrorを生成します。

掘り下げる

rdmd playground.d