英語版
このページの英語版を見る

std.range.primitives

このモジュールは std.range.
配列の双方向プリミティブと前方範囲プリミティブを定義する: empty, front, back, popFront, popBackそして save.
をテストするためのいくつかのテンプレートを定義することで、基本的な範囲化された関数を提供する。 与えられたオブジェクトが範囲であるかどうか、そしてどのような範囲であるかをテストするためのいくつかのテンプレートを定義することで、基本的な範囲の機能を提供する:
isInputRange 入力範囲であるかどうかをテストする。 プリミティブ 、 、 を使ってデータを順次読み取ることができる。 プリミティブfrontpopFrontempty を使ってデータを順次読み取ることができるものである。
isOutputRange 何かが出力範囲であるかどうかをテストする。 プリミティブを使用して順次データを書き込むことができる。 putプリミティブを使う。
isForwardRange 何かが順方向範囲であるかどうかをテストする。 入力範囲であるかどうかをテストする。 save プリミティブで現在位置を保存することができる。 プリミティブで現在位置を保存できる。
isBidirectionalRange あるものが双方向範囲であるかどうかをテストする。 プリミティブ backpopBack を使った逆方向走査が可能な順方向範囲であるかどうかをテストする。
isRandomAccessRange ランダムアクセス範囲であるかどうかを調べる。 プリミティブを使用した配列の添え字操作もサポートする。 opIndex 操作をサポートする双方向範囲である。
また、様々なレンジ機能をテストするテンプレートも多数用意されている:
hasMobileElements プリミティブを使用して、与えられた範囲の要素を移動できるかどうかをテストする。 プリミティブmoveFront,moveBack, またはmoveAt を使って、与えられた範囲の要素を移動できるかどうかをテストする。
ElementType 与えられた範囲の要素型を返す。
ElementEncodingType 与えられた範囲のエンコード要素型を返す。
hasSwappableElements 範囲がスワップ可能な要素を持つ順方向範囲であるかどうかを調べる。
hasAssignableElements 範囲が、変更可能な要素を持つ順方向範囲であるかどうかを調べる。
hasLvalueElements 範囲が、参照渡しが可能でアドレスが取得される要素を持つ順方向範囲であるかどうかを調べる。 前方範囲であるかどうかをテストする。
hasLength 与えられた範囲がlength 属性を持っているかどうかを調べる。
isInfinite 与えられた範囲が無限範囲であるかどうかを調べる。
hasSlicing 与えられた範囲が配列のスライス操作 R[x .. y] をサポートしているかどうかをテストする。
最後に、範囲を操作するためのいくつかの便利な関数が含まれている:
popFrontN 与えられた範囲を最大n個の要素で進める。
popBackN 与えられた双方向範囲を右から最大n要素進める。 n要素進める。
popFrontExactly 指定された範囲を正確にn要素まで進める。
popBackExactly 与えられた双方向の範囲を右からちょうど n要素進める。
moveFront 範囲の前の要素を削除する。
moveBack 双方向範囲の後方要素を削除する。
moveAt ランダムアクセス範囲のi番目の要素を削除する。
walkLength 任意の範囲の長さをO(n)時間で計算する。
put 要素e を範囲に出力する。
Authors:
Andrei Alexandrescu, David Simcha, and Jonathan M Davis. Credit for some of the ideas in building this module goes to Leonardo Maffi.
enum bool isInputRange(R);

enum bool isInputRange(R, E);
R が入力範囲である場合、true を返す。入力範囲には プリミティブemptypopFrontfront を定義していなければならない。以下のコードは 以下のコードは、どの入力範囲でもコンパイルできるはずである。
R r;              // 範囲オブジェクトを定義できる
if (r.empty) {}   // 空のテストができる
r.popFront();     // popFront()を呼び出すことができる
auto h = r.front; // 非void型の範囲の先頭を取得することができる
以下の入力範囲のルールは、すべての phobosのコードにおいて真であると仮定される。これらのルールはコンパイル時にチェックすることはできない。 範囲や範囲ベースのコードを書くときにこれらのルールに従わないと、未定義の動作になる。 未定義の動作になる。
  • r.empty 範囲内に利用可能なデータがさらにある場合に限り、 を返す。 を返す。false
  • r.empty を呼び出すことなく、複数回評価される。 を呼び出したり、範囲オブジェクトや基礎となるデータ を呼び出したり、範囲オブジェクトや基礎となるデータを変更したりすることなく、複数回評価された場合は、どの評価でも同じ結果が得られる。r.popFront
  • r.front は、範囲内の現在の要素を返す。 値で返すことも、参照で返すこともできる。
  • r.front を合法的に評価できるのは を評価することが、 と等しいか、等しかったであろう場合に限り、合法的に評価することができる。r.empty false
  • r.front を呼び出すことなく、複数回評価することができる。 を呼び出したり、範囲オブジェクトや基礎となるデータを変更したりすることなく、複数回評価された場合、同じ結果が得られる。 を呼び出したり、範囲オブジェクトや基礎となるデータに変更を加えたりすることなく、複数回評価されると、どの評価でも同じ結果が得られる。r.popFront
  • r.popFront は範囲の次の要素に進む。
  • r.popFront を呼び出すことができるのは を評価した結果、 と等しかった場合、または等しかったであろう場合にのみ呼び出される。r.empty false
また、Phobosのコードでは、プリミティブr.front および r.empty プリミティブは、Ο(1)時間複雑性、あるいは実行時間の点で「安価」である。 範囲関数のドキュメントにあるΟ()文はこの前提で作られている。 という記述がある。
See Also:
のヘッダーは std.rangeのチュートリアルを参照のこと。
Parameters:
R テストする型
E が存在する場合、その範囲の要素は次のものでなければならない。 でなければならない。 でなければならない。
Returns:
true Rが入力範囲(おそらく要素型 )である場合、そうでない場合は 。E false
Examples:
struct A {}
struct B
{
    void popFront();
    @property bool empty();
    @property int front();
}
static assert(!isInputRange!A);
static assert( isInputRange!B);
static assert( isInputRange!(int[]));
static assert( isInputRange!(char[]));
static assert(!isInputRange!(char[4]));
static assert( isInputRange!(inout(int)[]));
static assert(!isInputRange!(int[], string));
static assert( isInputRange!(int[], int));
static assert( isInputRange!(int[], const int));
static assert(!isInputRange!(int[], immutable int));

static assert(!isInputRange!(const(int)[], int));
static assert( isInputRange!(const(int)[], const int));
static assert(!isInputRange!(const(int)[], immutable int));

static assert(!isInputRange!(immutable(int)[], int));
static assert( isInputRange!(immutable(int)[], const int));
static assert( isInputRange!(immutable(int)[], immutable int));

static struct NotDefaultConstructible
{
    @disable this();
    void popFront();
    @property bool empty();
    @property int front();
}
static assert( isInputRange!NotDefaultConstructible);

static struct NotDefaultConstructibleOrCopyable
{
    @disable this();
    @disable this(this);
    void popFront();
    @property bool empty();
    @property int front();
}
static assert(isInputRange!NotDefaultConstructibleOrCopyable);

static struct Frontless
{
    void popFront();
    @property bool empty();
}
static assert(!isInputRange!Frontless);

static struct VoidFront
{
    void popFront();
    @property bool empty();
    void front();
}
static assert(!isInputRange!VoidFront);
void put(R, E)(ref R r, E e);
出力 eを出力する。 r.正確な効果は 型に依存する。以下に説明するように、いくつかのケースが受け入れられる。コード・スニペット は順番に試行され、最初にコンパイルされたものが「勝ち」となり、評価される。 評価される。
この表では、"doPut"はメソッドで eを置くメソッドである。 rに置くメソッドである。 に置くメソッドである: r.put(e)もしRput,r.front = e を定義する。 rが入力範囲(その後に r.popFront())、または r(e) でなければ
コード・スニペット シナリオ
r.doPut(e); R 特に を受け入れる。E
r.doPut([ e ]); R 具体的には、 。E[]
r.putChar(e); R putは以下のような文字列や文字を受け取る。 文字をトランスコードする。 eに変換する。
for (; !e.empty; e.popFront()) put(r, e.front); E の範囲をR にコピーする。

チップ putは "UFCSスタイル"で使ってはいけないr.put(e). このようにすると R.putが提供する変換機能をバイパスして が提供する変換機能をバイパスして直接呼び出すことができる。 Range.putput(r, e)

Examples:
出力範囲の putメソッドが"型"の要素しか受け入れない場合、グローバルな "型"を使用する。 T 型の要素しか受け付けない場合、グローバル putを使用して、T[] を範囲 への出力を処理する。
import std.traits : isSomeChar;

static struct A
{
    string data;

    void put(C)(C c) if (isSomeChar!C)
    {
        data ~= c;
    }
}
static assert(isOutputRange!(A, char));

auto a = A();
put(a, "Hello");
writeln(a.data); // "Hello"
Examples:
putは動的配列を配列スライスとして扱い、要素をコピーした後にスライスに対してpopFront を呼び出す。
を呼び出す前に、必ず配列の位置を保存しておくこと。 put.
int[] a = [1, 2, 3], b = [10, 20];
auto c = a;
put(a, b);
writeln(c); // [10, 20, 3]
// この時点で、aは2回進んでいるので、最後の要素しか
// 含まれていないが、cは配列全体を表している
writeln(a); // [3]
Examples:
また、以下のことも可能である。 put文字列や文字を幅の狭い 文字列に変換することもできる。
ターゲット・バッファ型と同じ幅の文字をputすることに注意されたい。 nothrow をスローすることがある。 std.utf.UTFException.
// 要素は変更可能でなければならないので、stringやconst(char)[]を使っても
// コンパイルできない
char[] s1 = new char[13];
auto r1 = s1;
put(r1, "Hello, World!"w);
writeln(s1); // "Hello, World!"
enum bool isOutputRange(R, E);
R が型の要素の出力範囲である場合、true を返す。 E.出力範囲は、上記で定義された の操作をサポートする範囲として機能的に定義される。 put(r, e) をサポートする範囲として機能的に定義される。
See Also:
のヘッダを参照のこと。 std.rangeのヘッダーを参照のこと。
Examples:
void myprint(scope const(char)[] s) { }
static assert(isOutputRange!(typeof(&myprint), char));

static assert( isOutputRange!(char[], char));
static assert( isOutputRange!(dchar[], wchar));
static assert( isOutputRange!(dchar[], dchar));
enum bool isForwardRange(R);

enum bool isForwardRange(R, E);
R が前方範囲ならtrue を返す。前方範囲とは 入力範囲rr.save を別の"型"の値R に保存することによって、"チェックポイント"を保存することができる入力範囲である。順方向範囲でない入力範囲の"例"は、ファイル/ソケット範囲である。 このような範囲をコピーしても、その範囲の位置は保存されない。 このような範囲をコピーしても、ストリーム内の位置は保存されない。 このような範囲をコピーしても、ストリーム内の位置は保存されない。 このような範囲をコピーしても、ストリーム内の位置は保存されない。このような範囲をコピーしても、ストリーム内の位置は保存されない。 を進めることになるので、コピーは独立していない。
以下のコードは、どの前方範囲でもコンパイルできるはずである。
static assert(isInputRange!R);
R r1;
auto s1 = r1.save;
static assert(is(typeof(s1) == R));
範囲を保存することは、その範囲を複製することではない、r1 上記の例では、r2 はまだ同じ基礎データを参照している。それらはただ と。
前方範囲(コンパイル時にチェックできない)のセマンティクスは、入力範囲と同じである。 のセマンティクスは入力範囲と同じである。 バックトラックは、範囲オブジェクトのコピーを。 オブジェクトのコピーをsave
save は多くの点でコピー・コンストラクタのように振る舞う。 の実装は、通常コピー・コンストラクションを使って行われる。
しかし、コピーコンストラクタがあるからといって、その範囲が前方範囲であるとは限らない。 が順方向範囲であることを意味するわけではない。例えば、TTYから読み込む範囲である。 TTYから読み取る範囲は、その入力を消費し、その場所を保存して再び読み取ることはできない。 そのため前方範囲にはならず、 関数を持つこともできない。 save関数を持つことはできない。
See Also:
のヘッダーは std.rangeのチュートリアルを参照のこと。
Parameters:
R テストする型
E が存在する場合、その範囲の要素は次のものでなければならない。 でなければならない。 でなければならない。
Returns:
true Rが前方範囲(おそらく要素型 )の場合、そうでない場合は 。E false
Examples:
static assert(!isForwardRange!(int));
static assert( isForwardRange!(int[]));
static assert( isForwardRange!(inout(int)[]));

static assert( isForwardRange!(int[], const int));
static assert(!isForwardRange!(int[], immutable int));

static assert(!isForwardRange!(const(int)[], int));
static assert( isForwardRange!(const(int)[], const int));
static assert(!isForwardRange!(const(int)[], immutable int));

static assert(!isForwardRange!(immutable(int)[], int));
static assert( isForwardRange!(immutable(int)[], const int));
static assert( isForwardRange!(immutable(int)[], immutable int));
enum bool isBidirectionalRange(R);

enum bool isBidirectionalRange(R, E);
R が双方向範囲の場合、true を返す。双方向 プリミティブback も提供する。 popBack.以下のコードは、あらゆる双方向の 範囲に対してコンパイルされるはずである。
双方向範囲のセマンティクス(コンパイル時にはチェックできない)は以下のように仮定される。 r )のセマンティクスは以下のように仮定される。 R型である):
  • r.back 範囲の最後の の参照を返す。 。 を返した場合、または返したであろう場合にのみ、 を呼び出すことができる。r.backr.empty false
See Also:
のヘッダーは std.rangeのチュートリアルを参照のこと。
Parameters:
R テストする型
E が存在する場合、その範囲の要素は次のものでなければならない。 でなければならない。 でなければならない。
Returns:
true R が双方向の範囲(要素型が である場合もある)であれば、 。E false
Examples:
alias R = int[];
R r = [0,1];
static assert(isForwardRange!R);           // は前方範囲である
r.popBack();                               // popBackを呼び出すことができる
auto t = r.back;                           // 呼び出すことで、範囲の後ろを取得することができる
auto w = r.front;
static assert(is(typeof(t) == typeof(w))); // 前後に同じ型がある

// 要素の型をチェックする
static assert( isBidirectionalRange!(int[], const int));
static assert(!isBidirectionalRange!(int[], immutable int));

static assert(!isBidirectionalRange!(const(int)[], int));
static assert( isBidirectionalRange!(const(int)[], const int));
static assert(!isBidirectionalRange!(const(int)[], immutable int));

static assert(!isBidirectionalRange!(immutable(int)[], int));
static assert( isBidirectionalRange!(immutable(int)[], const int));
static assert( isBidirectionalRange!(immutable(int)[], immutable int));
enum bool isRandomAccessRange(R);

enum bool isRandomAccessRange(R, E);
R がランダムアクセス範囲の場合、true を返す。ランダムアクセス 範囲とは、プリミティブopIndex も提供する双方向の範囲、またはopIndex を提供する無限前方範囲のことである。いずれの場合も どちらの場合も、その範囲はlength を提供するか、無限でなければならない。 無限でなければならない。以下のコードは、どのランダムアクセス範囲でもコンパイルできるはずである。 範囲についてコンパイルする必要がある。
ランダムアクセス範囲のセマンティクス(コンパイル時にはチェックできない )のセマンティクスは以下のように仮定される(rR型である):
  • r.opIndex(n) への参照を返す。 への参照を返す。n
char[]wchar[] (および 、 などの修飾バージョン)は配列である。 stringwstring を含む)は配列であるが、isRandomAccessRangefalse は可変長エンコーディング(それぞれ UTF-8とUTF-16)を使用しているため、 は配列である。 可変長エンコーディング(それぞれUTF-8とUTF-16)を使用しているためである。これらの型は、双方向の範囲のみである。 は双方向の範囲のみである。
See Also:
のヘッダーは std.rangeのチュートリアルを参照のこと。
Parameters:
R テストする型
E が存在する場合、その範囲の要素は次のものでなければならない。 でなければならない。 でなければならない。
Returns:
true Rがランダムアクセス可能な範囲(おそらく要素型 )である場合、そうでない場合は 。E false
Examples:
import std.traits : isAggregateType, isAutodecodableString;

alias R = int[];

// 範囲が有限で双方向か、無限で順方向か。
static assert(isBidirectionalRange!R ||
              isForwardRange!R && isInfinite!R);

R r = [0,1];
auto e = r[1]; // インデックスできる
auto f = r.front;
static assert(is(typeof(e) == typeof(f))); // インデックス付きもフロントも同じ型である
static assert(!(isAutodecodableString!R && !isAggregateType!R)); // 狭い文字列は範囲としてインデックスできない
static assert(hasLength!R || isInfinite!R); // 長さがあるか、無限でなければならない

// opIndexが$で動作する場合、$は配列と同じように動作しなければならない
static if (is(typeof(r[$])))
{
    static assert(is(typeof(f) == typeof(r[$])));

    // $ - 1は無限の範囲では意味をなさないが、有限の範囲では
    // 機能する必要がある。
    static if (!isInfinite!R)
        static assert(is(typeof(f) == typeof(r[$ - 1])));
}

// 要素型をチェックする
static assert( isRandomAccessRange!(int[], const int));
static assert(!isRandomAccessRange!(int[], immutable int));

static assert(!isRandomAccessRange!(const(int)[], int));
static assert( isRandomAccessRange!(const(int)[], const int));
static assert(!isRandomAccessRange!(const(int)[], immutable int));

static assert(!isRandomAccessRange!(immutable(int)[], int));
static assert( isRandomAccessRange!(immutable(int)[], const int));
static assert( isRandomAccessRange!(immutable(int)[], immutable int));
enum bool hasMobileElements(R);
R がプリミティブをサポートする入力範囲である場合、true を返す。 moveFront moveAt プリミティブをサポートする入力範囲であればmoveBack を返す。 を返す。これらは明示的に実装されている場合もあれば モジュール・レベル関数のデフォルト動作で動作する。moveFront やフレンド関数のデフォルト動作で動作する。以下のコードは でコンパイルできるはずだ。
alias E = ElementType!R;
R r;
static assert(isInputRange!R);
static assert(is(typeof(moveFront(r)) == E));
static if (isBidirectionalRange!R)
    static assert(is(typeof(moveBack(r)) == E));
static if (isRandomAccessRange!R)
    static assert(is(typeof(moveAt(r, 0)) == E));
Examples:
import std.algorithm.iteration : map;
import std.range : iota, repeat;

static struct HasPostblit
{
    this(this) {}
}

auto nonMobile = map!"a"(repeat(HasPostblit.init));
static assert(!hasMobileElements!(typeof(nonMobile)));
static assert( hasMobileElements!(int[]));
static assert( hasMobileElements!(inout(int)[]));
static assert( hasMobileElements!(typeof(iota(1000))));

static assert( hasMobileElements!( string));
static assert( hasMobileElements!(dstring));
static assert( hasMobileElements!( char[]));
static assert( hasMobileElements!(dchar[]));
template ElementType(R)
R.R の要素型は範囲である必要はない。要素タイプは の要素型は、r.front が返す型として決定される。 Rオブジェクトr の型として決定される。例:」である、 ElementType!(T[])T である。もしT[] が狭い文字列でなければ、要素型は dchar.Rfront を持っていない、 ElementType!Rである。 void.
Examples:
import std.range : iota;

// 標準配列: 配列の要素の型を返す
static assert(is(ElementType!(int[]) == int));

// .frontにアクセスすると、デコードされたdcharを取り出す
static assert(is(ElementType!(char[])  == dchar)); // rvalue
static assert(is(ElementType!(dchar[]) == dchar)); // lvalue

// 同上
static assert(is(ElementType!(string) == dchar));
static assert(is(ElementType!(dstring) == immutable(dchar)));

// レンジの場合、.frontの型を取得する。
auto range = iota(0, 10);
static assert(is(ElementType!(typeof(range)) == int));
template ElementEncodingType(R)
エンコーディング要素の型はR である。 狭い文字列 (char[]wchar[] およびstringwstring), ElementEncodingTypeの文字型である。 文字列の文字型である。他のすべての型では、"型"は文字列の文字型である、 ElementEncodingTypeと同じである。 ElementType.
Examples:
import std.range : iota;
// 内部的には、範囲はエンコードされた型を格納している
static assert(is(ElementEncodingType!(char[])  == char));

static assert(is(ElementEncodingType!(wstring) == immutable(wchar)));

static assert(is(ElementEncodingType!(byte[]) == byte));

auto range = iota(0, 10);
static assert(is(ElementEncodingType!(typeof(range)) == int));
enum bool hasSwappableElements(R);
R が入力範囲であり、スワップ可能な要素を持つ場合はtrue を返す。 要素を持つ場合に返す。以下のコードは に対してコンパイルできるはずである。
R r;
static assert(isInputRange!R);
swap(r.front, r.front);
static if (isBidirectionalRange!R) swap(r.back, r.front);
static if (isRandomAccessRange!R) swap(r[0], r.front);
Examples:
static assert(!hasSwappableElements!(const int[]));
static assert(!hasSwappableElements!(const(int)[]));
static assert(!hasSwappableElements!(inout(int)[]));
static assert( hasSwappableElements!(int[]));

static assert(!hasSwappableElements!( string));
static assert(!hasSwappableElements!(dstring));
static assert(!hasSwappableElements!( char[]));
static assert( hasSwappableElements!(dchar[]));
enum bool hasAssignableElements(R);
R が入力範囲であり、かつ変更可能な要素を持つ場合、true を返す。 要素を持つ場合に返す。以下のコードは に対してコンパイルできるはずである。
R r;
static assert(isInputRange!R);
r.front = r.front;
static if (isBidirectionalRange!R) r.back = r.front;
static if (isRandomAccessRange!R) r[0] = r.front;
Examples:
static assert(!hasAssignableElements!(const int[]));
static assert(!hasAssignableElements!(const(int)[]));
static assert( hasAssignableElements!(int[]));
static assert(!hasAssignableElements!(inout(int)[]));

static assert(!hasAssignableElements!( string));
static assert(!hasAssignableElements!(dstring));
static assert(!hasAssignableElements!( char[]));
static assert( hasAssignableElements!(dchar[]));
enum bool hasLvalueElements(R);
範囲R がl値要素を持つかどうかをテストする。これらは 要素として定義されている。 以下のコードは、lvalue要素を持つどの範囲に対してもコンパイルできるはずである。
void passByRef(ref ElementType!R stuff);
...
static assert(isInputRange!R);
passByRef(r.front);
static if (isBidirectionalRange!R) passByRef(r.back);
static if (isRandomAccessRange!R) passByRef(r[0]);
template hasLength(R)
Rlength の値を返すメンバがあれば、true を返す。size_t R 。範囲である必要はない。R が範囲である場合、標準ライブラリのアルゴリズムは 型の のみをサポートすることが保証される。 標準ライブラリのアルゴリズムは、size_t 型を持つlength のみをサポートすることが保証されている。
どの範囲も実装してはならないので、length はオプションのプリミティブであることに注釈:。いくつかの 範囲によってはその長さを明示的に保存しないものもあるし、実際に範囲を使い切らなければ計算できないものもある。 を計算できないものもある(ソケットストリームなど)。 は無限である。
狭い文字列型(char[]wchar[] 、およびそれらの修飾子)は、 プロパティを定義している。 およびその修飾型)は、length " プロパティを定義している、 hasLengthfalse 。 これは、ナロー文字列の長さが文字数ではなく、エンコード単位数を反映するためである。 これは、狭い文字列の長さが文字数を反映するのではなく、エンコード単位の数を反映するためである。 範囲指向のアルゴリズムでは役に立たない。文字列を 長さを持つランダムアクセス範囲として文字列を使うには std.string.representationまたは std.utf.byCodeUnit.
Examples:
static assert(!hasLength!(char[]));
static assert( hasLength!(int[]));
static assert( hasLength!(inout(int)[]));

struct A { size_t length() { return 0; } }
struct B { @property size_t length() { return 0; } }
static assert( hasLength!(A));
static assert( hasLength!(B));
template isInfinite(R)
R が無限入力範囲の場合、true を返す。無限入力範囲とは 無限入力範囲とは、常に である という静的に定義された列挙メンバを持つ入力範囲のことである。 empty falseと呼ばれる列挙メンバを持つ入力範囲である、 例:」である:
struct MyInfiniteRange
{
    enum bool empty = false;
    ...
}
Examples:
import std.range : Repeat;
static assert(!isInfinite!(int[]));
static assert( isInfinite!(Repeat!(int)));
enum bool hasSlicing(R);
R が、前方範囲型を返す積分境界を持つスライス演算子を提供している場合、true を返す。 を返す。
有限範囲の場合、opSlice の結果は元の範囲型と同じ型でなければならない。 元の範囲型と同じ型でなければならない。範囲がopDollar を定義している場合、それは減算をサポートしていなければならない。 減算をサポートしなければならない。
無限範囲では、opDollar を使用しない場合、 の結果は任意の型の前方範囲となる。opSlice の結果は、任意の型の前方範囲でよい。しかし、opDollar を使用する場合、 の結果は、元の範囲型と同じ型でなければならない。 opSlice の結果は、元の範囲型と同じ型でなければならない。
が であるためには、以下の式が真でなければならない。 hasSlicingtrueが真でなければならない:
    isForwardRange!R
    && !(isAutodecodableString!R && !isAggregateType!R)
    && is(typeof((R r) { return r[1 .. 1].length; } (R.init)) == size_t)
    && (is(typeof(lvalueOf!R[1 .. 1]) == R) || isInfinite!R)
    && (!is(typeof(lvalueOf!R[0 .. $])) || is(typeof(lvalueOf!R[0 .. $]) == R))
    && (!is(typeof(lvalueOf!R[0 .. $])) || isInfinite!R
        || is(typeof(lvalueOf!R[0 .. $ - 1]) == R))
    && is(typeof((ref R r)
    {
        static assert(isForwardRange!(typeof(r[1 .. 2])));
    }));
Examples:
import std.range : takeExactly;
static assert( hasSlicing!(int[]));
static assert( hasSlicing!(const(int)[]));
static assert(!hasSlicing!(const int[]));
static assert( hasSlicing!(inout(int)[]));
static assert(!hasSlicing!(inout int []));
static assert( hasSlicing!(immutable(int)[]));
static assert(!hasSlicing!(immutable int[]));
static assert(!hasSlicing!string);
static assert( hasSlicing!dstring);

enum rangeFuncs = "@property int front();" ~
                  "void popFront();" ~
                  "@property bool empty();" ~
                  "@property auto save() { return this; }" ~
                  "@property size_t length();";

struct A { mixin(rangeFuncs); int opSlice(size_t, size_t); }
struct B { mixin(rangeFuncs); B opSlice(size_t, size_t); }
struct C { mixin(rangeFuncs); @disable this(); C opSlice(size_t, size_t); }
struct D { mixin(rangeFuncs); int[] opSlice(size_t, size_t); }
static assert(!hasSlicing!(A));
static assert( hasSlicing!(B));
static assert( hasSlicing!(C));
static assert(!hasSlicing!(D));

struct InfOnes
{
    enum empty = false;
    void popFront() {}
    @property int front() { return 1; }
    @property InfOnes save() { return this; }
    auto opSlice(size_t i, size_t j) { return takeExactly(this, j - i); }
    auto opSlice(size_t i, Dollar d) { return this; }

    struct Dollar {}
    Dollar opDollar() const { return Dollar.init; }
}

static assert(hasSlicing!InfOnes);
auto walkLength(Range)(Range range)
if (isInputRange!Range && !isInfinite!Range);

auto walkLength(Range)(Range range, const size_t upTo)
if (isInputRange!Range);
これは、length のベストエフォート実装である。 の範囲のためのベストエフォート実装である。
もしhasLength!Range 、単に range.lengthを返す。 をチェックせずに返す。 upTo(指定された場合)。
そうでない場合は、範囲をその長さだけ歩き、見た要素の数を返す。 を返す。をΟ(n) 回評価する。 range.empty の評価を実行する。 range.popFront()nrange の有効長である。
である。 upToパラメータは、次のような場合に "損切り"に役立つ。 このパラメータは、範囲が少なくともいくつかの要素を持つかどうかを見ることに興味がある場合に、「損失を削減」するのに便利である。 の要素を持つかどうかを見ることにある。パラメータ upToが指定された場合、upTo ステップが取られた場合に停止して upTo.
パラメータ upToパラメータ その場合、実装は単純に upTo を返す。
Examples:
import std.range : iota;

writeln(10.iota.walkLength); // 10
// iotaはlength関数を持っているので、歩行する
// 必要はなく、upToパラメータは
// 無視される
writeln(10.iota.walkLength(5)); // 10
size_t popFrontN(Range)(ref Range r, size_t n)
if (isInputRange!Range);

size_t popBackN(Range)(ref Range r, size_t n)
if (isBidirectionalRange!Range);
popFrontN熱心に前進する rまで前進する。 n回 (を呼び出す)。 r.popFront). popFrontNを取る。 rref 、 つまり、元の範囲を変更する。1で完了する ステップで完了する。 それ以外の範囲については、Ο(n)ステップで完了する。
popBackNpopFrontNと同じ振る舞いをするが、代わりに と同じ振る舞いをするが、代わりに(双方向)範囲の前方ではなく後方から要素を取り除く。
Returns:
実際にはいくらだったのだろうか。 rを下回るかもしれない。 nもし r少なくとも n要素を持っていなかった場合よりも少なくなる可能性がある。
Examples:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popFrontN(2);
writeln(a); // [3, 4, 5]
a.popFrontN(7);
writeln(a); // []
Examples:
import std.algorithm.comparison : equal;
import std.range : iota;
auto LL = iota(1L, 7L);
auto r = popFrontN(LL, 2);
assert(equal(LL, [3L, 4L, 5L, 6L]));
writeln(r); // 2
Examples:
int[] a = [ 1, 2, 3, 4, 5 ];
a.popBackN(2);
writeln(a); // [1, 2, 3]
a.popBackN(7);
writeln(a); // []
Examples:
import std.algorithm.comparison : equal;
import std.range : iota;
auto LL = iota(1L, 7L);
auto r = popBackN(LL, 2);
assert(equal(LL, [1L, 2L, 3L, 4L]));
writeln(r); // 2
void popFrontExactly(Range)(ref Range r, size_t n)
if (isInputRange!Range);

void popBackExactly(Range)(ref Range r, size_t n)
if (isBidirectionalRange!Range);
熱心に前進する rコピーではない n回前進する。 呼び出す r.popFront). popFrontExactlyを取る。 rref 、 つまり、元の範囲を変更する。1完了する。 ステップで完了する。 それ以外の範囲では、Ο(n)ステップで完了する。

注釈 とは異なり popFrontN, popFrontExactlyとは異なり は少なくとも n要素を持つと仮定する。そのため popFrontExactly これはpopFrontN よりも高速だが、range が少なくとも要素を含んでいない場合 が少なくとも n要素を含まない場合、空の範囲に対してpopFront これは未定義の動作である。そのため popFrontExactlyを使うのは、range が少なくとも n要素を保持することが保証されている場合にのみ使用すること。

popBackExactlyも同じ動作をするが、その代わりに(双方向の)範囲の前方ではなく後方から要素を削除する。 の要素を削除する。

Examples:
import std.algorithm.comparison : equal;
import std.algorithm.iteration : filterBidirectional;

auto a = [1, 2, 3];
a.popFrontExactly(1);
writeln(a); // [2, 3]
a.popBackExactly(1);
writeln(a); // [2]

string s = "日本語";
s.popFrontExactly(1);
writeln(s); // "本語"
s.popBackExactly(1);
writeln(s); // "本"

auto bd = filterBidirectional!"true"([1, 2, 3]);
bd.popFrontExactly(1);
assert(bd.equal([2, 3]));
bd.popBackExactly(1);
assert(bd.equal([2]));
ElementType!R moveFront(R)(R r);
の前を移動して戻す。 rの前を移動して返す。
もし r.frontがデストラクタまたはコピーコンストラクタが定義された構造体である場合、その値は移動された後にリセットされる。 は、その値が移動された後、.init の値にリセットされる。そうでない場合は は変更されない。
どちらの場合も r.frontは破棄可能な状態で残される。 になる。
Examples:
auto a = [ 1, 2, 3 ];
writeln(moveFront(a)); // 1
writeln(a.length); // 3

// 形式的な入力範囲を定義する
struct InputRange
{
    enum bool empty = false;
    enum int front = 7;
    void popFront() {}
    int moveFront() { return 43; }
}
InputRange r;
// r.moveFrontを呼び出す
writeln(moveFront(r)); // 43
ElementType!R moveBack(R)(R r);
の背面を移動して戻す。 rを外に出して返す。残す r.backを残す。 リソースを割り当てない破棄可能な状態で残す(通常 .init の値)を割り当てない破壊可能な状態で残す。
Examples:
struct TestRange
{
    int payload = 5;
    @property bool empty() { return false; }
    @property TestRange save() { return this; }
    @property ref int front() return { return payload; }
    @property ref int back() return { return payload; }
    void popFront() { }
    void popBack() { }
}
static assert(isBidirectionalRange!TestRange);
TestRange r;
auto x = moveBack(r);
writeln(x); // 5
ElementType!R moveAt(R)(R r, size_t i);
のインデックス irの要素を移動して返す。 r[i] 、リソースを割り当てない破棄可能な状態で残す。 (通常は.init の値に等しい)。
Examples:
auto a = [1,2,3,4];
foreach (idx, it; a)
{
    writeln(it); // moveAt(a, idx)
}
@property bool empty(T)(auto ref scope T a)
if (is(typeof(a.length) : size_t));
範囲インターフェイス・プリミティブを実装する。 emptyプリミティブを実装している。 プリミティブを実装する。 hasLengthプリミティブを実装する。そのため 非メンバー関数は第1引数で呼び出すことができる。 をドット表記で呼び出すことができる、 a.emptyと等価である。 empty(a).
Examples:
auto a = [ 1, 2, 3 ];
assert(!a.empty);
assert(a[3 .. $].empty);

int[string] b;
assert(b.empty);
b["zero"] = 0;
assert(!b.empty);
pure nothrow @nogc @property @safe inout(T)[] save(T)(return scope inout(T)[] a);
範囲インターフェースプリミティブを実装する saveプリミティブを実装している。 プリミティブを実装している。非メンバー関数はドット記法で第1引数を呼び出すことができる。 で呼び出すことができる、 array.saveは と等価である。 save(array).と等価である。 単に引数を返すだけである。
Examples:
auto a = [ 1, 2, 3 ];
auto b = a.save;
assert(b is a);
pure nothrow @nogc @safe void popFront(T)(ref scope inout(T)[] a)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure nothrow @trusted void popFront(C)(ref scope inout(C)[] str)
if (isAutodecodableString!(C[]));
レンジ・インターフェイス・プリミティブを実装する popFrontプリミティブを実装している。 プリミティブを実装している。非メンバー関数はドット記法で第1引数を呼び出すことができる。 で呼び出すことができる、 array.popFrontは と等価である。 popFront(array).狭い文字列の場合 popFrontは自動的に次のコードポイントに進む。 ポイントに進む。
Examples:
auto a = [ 1, 2, 3 ];
a.popFront();
writeln(a); // [2, 3]
pure nothrow @nogc @safe void popBack(T)(ref scope inout(T)[] a)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure @safe void popBack(T)(ref scope inout(T)[] a)
if (isAutodecodableString!(T[]));
レンジ・インターフェイス・プリミティブを実装する popBackプリミティブを実装している。 プリミティブを実装している。非メンバー関数はドット記法で第1引数を呼び出すことができる。 で呼び出すことができる、 array.popBackは と等価である。 popBack(array).狭い文字列の場合、popFront は自動的に最後のコードポイントを削除する。
Examples:
auto a = [ 1, 2, 3 ];
a.popBack();
writeln(a); // [1, 2]
enum bool autodecodeStrings;

実験的 自動デコードの削除を試すには、バージョンを次のように設定する。 NoAutodecodeStrings.このバージョンではほとんどのことが失敗する このバージョンでは、ほとんどのことが失敗すると予想される。

pure nothrow @nogc @property ref @safe inout(T) front(T)(return scope inout(T)[] a)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure @property @safe dchar front(T)(scope const(T)[] a)
if (isAutodecodableString!(T[]));
レンジ・インターフェイス・プリミティブを実装する frontプリミティブを実装している。 プリミティブを実装している。非メンバー関数をドット記法で呼び出すことができる。 で呼び出すことができる、 array.frontは と等価である。 front(array).狭い文字列の場合、front は自動的に最初のコードポイントをdchar として返す。
Examples:
int[] a = [ 1, 2, 3 ];
writeln(a.front); // 1
pure nothrow @nogc @property ref @safe inout(T) back(T)(return scope inout(T)[] a)
if (!isAutodecodableString!(T[]) && !is(T[] == void[]));

pure @property @safe dchar back(T)(scope const(T)[] a)
if (isAutodecodableString!(T[]));
範囲インターフェースプリミティブを実装する backプリミティブを実装している。 プリミティブを実装している。非メンバー関数はドット記法で第1引数を呼び出すことができる。 で呼び出すことができる、 array.backは と等価である。 back(array).狭い文字列の場合、back は自動的に最後のコードポイントをdchar として返す。
Examples:
int[] a = [ 1, 2, 3 ];
writeln(a.back); // 3
a.back += 4;
writeln(a.back); // 7