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

Expression:
    CommaExpression

式とは、演算子とオペランドのシーケンスで、評価を指定するものである。 式の構文、評価の順序、および意味は以下の通りである。

式は、結果の型を持つ値を計算するために使用される。 これらの値は、その後、割り当て、 テスト、または無視することができる。式には副作用がある場合もある。

定義と用語

完全な式

任意の式 expr の完全な式は、以下のように定義される。expr が 他の式expr1 の部分式として解析される場合、expr の完全な式は expr の完全な式

任意の式 expr について、expr の完全な式は以下のように定義される。expr が 他の式expr1 の部分式として解析される場合、expr の完全な式は expr1 の完全な式となる。それ以外の場合、exprはそれ自身の完全な式となる。

各式には、それぞれ独自の完全な式がある。 例:

return f() + g() * 2;

上のg() * 2 の完全な式はf() + g() * 2 であるが、f() + g() の完全な式ではない。なぜなら、後者は部分式として解析されないからである。

注釈: 定義は単純明快だが、関数リテラルにはいくつかの微妙な点がある。

return (() => x + f())() * g();

上のf() の完全な式はx + f() であり、return に渡される式ではない。 これは、x + f() の親が関数リテラル型であり、式型ではないためである。

lvalue

以下の式、およびそれ以外は、lvalue式またはlvalueと呼ばれる。

xml-ph-0000@deepl.internalおよびxml-ph-0001@deepl.internalのメンバ関数内にあるもの。
  1. thisstruct およびunion のメンバ関数内、
  2. 参照を返す変数、関数名、または関数の呼び出し、
  3. . PostfixExpressionおよび モジュールスコープ演算子 の、ドットの右辺が変数、フィールド(直接またはstatic )、関数名、または参照を返す関数の呼び出しである場合の
  4. 以下の式の結果:

r値

l値ではない式はr値である。r値には、すべてのリテラル、__FILE____LINE__ などの特別な値キーワード、enum 値、および上記でl値として定義されていない式の結果が含まれる。

組み込みのアドレス・オブ・オペレータ(単項演算子& )は、l値にのみ適用できる。

最小の短絡式

fullexprという完全な式の部分式である式expr 与えられた場合、 最小のショートサーキット式は 、fullexprの AndAndExpression(&&) または OrOrExpression(||)であり、かつ、expr がscexprの部分式であるような、fullexprの最短の部分式scexprである。 例:

((f() * 2 && g()) + 1) || h()
上の部分式f() * 2 の最小の短絡式はf() * 2 && g() である。例:
(f() && g()) + h()
上の部分式h() には最小の短絡式はない。

評価の順序

組み込みの接頭辞単項式++ および-- は、以下のように代入にダウンス(書き換え)されたかのように評価される。

ExpressionEquivalent
++expr((expr) += 1)
--expr((expr) -= 1)

したがって、接頭辞++-- の結果は、副作用が実行された後の"l値"となる。

組み込みのポストフィックス単項式++-- は、以下のように、ラムダ呼び出しに変換(書き換え)されたかのように評価される。

ExpressionEquivalent
expr++(ref x){auto t = x; ++x; return t;}(expr)
expr--(ref x){auto t = x; --x; return t;}(expr)

したがって、postfix++-- の結果は、副作用が発生する直前に"r値"となる。

AssignExpression 、OrOrExpression、AndAndExpression以外の2項式は、 ()()順(左から右)で評価される。 例:xml-ph-0000@deepl.internal

int i = 2;
i = ++i * i++ + i;
assert(i == 3 * 3 + 4);

OrOrExpressionおよびAndAndExpressionは、まず左辺の引数を評価する。 次に、OrOrExpressionは、左辺がゼロ以外を評価しない場合にのみ、右辺を評価する。 AndAndExpressionは、左辺がゼロ以外を評価する場合にのみ、右辺を評価する。

ConditionalExpression はまず左辺の引数を評価する。 次に、その結果がゼロ以外の場合、2番目のオペランドが評価される。そうでない場合は、3番目のオペランドが 評価される。

extern(D) リンク(これは デフォルトのリンク)を持つ関数への呼び出しは、以下の順序で評価される。まず、必要に応じて、呼び出す関数のアドレスが 評価される(例えば、計算された関数ポインタやデリゲートのケース)。次に、 引数が左から右の順に評価される。最後に、転送が関数に渡される。例:

void function(int a, int b, int c) fun()
{
    writeln("fun() called");
    static void r(int a, int b, int c) { writeln("callee called"); }
    return &r;
}
int f1() { writeln("f1() called"); return 1; }
int f2() { writeln("f2() called"); return 2; }
int f3(int x) { writeln("f3() called"); return x + 3; }
int f4() { writeln("f4() called"); return 4; }

// fun()が評価され、次にf1()が評価され、次にf2()が評価され、次にf3()が評価され、次にf4()が評価される
// その後、制御は呼び出し側に移される
fun()(f1(), f3(f2()), f4());
Implementation Defined:
  1. AssignExpressionのオペランドの評価順序。
  2. extern (D) 以外のリンクを持つ関数の関数引数の評価順序。
Best Practices: 評価順序が明確に定義されているとしても、 それを前提としたコードの記述は推奨されない。 xml-ph-0000@deepl.internal

一時的なものの寿命

式や文は、r値を生成したり、r値を消費したりすることがある。そのような値は 一時値と呼ばれ、名前を持たず、可視スコープを持たない。その寿命は、 このセクションで定義されているように、自動的に管理される。

一時的な値を生成する評価のそれぞれについて、その一時的な値の有効期間はその評価時点から開始される。 これは、式で初期化された通常の名前付き値の生成と同様である。

一時変数の有効期間の終了は、通常のスコープのルールに従わず、 以下のように定義される。

式のサブ式が例外をスローした場合、そのサブ式の評価までに作成されたすべてのテンポラリは、 上記の規則に従って破棄される。 まだ構築されていないテンポラリに対しては、デストラクタの呼び出しは発行されない。

注釈: これらの規則の背景にある考え方は、一時変数のデストラクタは完全な式の最後に、 構築の逆順で遅延されるというものである。ただし、&&|| の右辺は、より大きな式の一部であっても、それ自体が完全な式として扱われる。

注釈:ConditionalExpression e1 ? e2 : e3は、 条件付きで式を評価する特殊なケースではない。e1 e2 および e3 のいずれかによって一時オブジェクトが作成される可能性がある。それらのデストラクタは、 作成された順序とは逆の順序で完全な式の最後に挿入される。

例:

import std.stdio;

struct S
{
    int x;
    this(int n) { x = n; writefln("S(%s)", x); }
    ~this() { writefln("~S(%s)", x); }
}

void main()
{
    bool b = (S(1) == S(2) || S(3) != S(4)) && S(5) == S(6);
}
上記のコードの出力は次のとおりである。
S(1)
S(2)
S(3)
S(4)
~S(4)
~S(3)
S(5)
S(6)
~S(6)
~S(5)
~S(2)
~S(1)
まず、S(1)S(2)()()順に評価される。ルールに従って、これらは 式全体が終了した時点で、逆順に破棄される。S(1) == S(2) の比較はfalse を生成するため、|| の右辺が評価され、S(3)S(4) が評価される。 これも()()順である。しかし、これらの破棄は式全体の終了まで延期されない 。代わりに、S(4) 、次にS(3) は、|| 式の終了時に破棄される。 破棄後、S(5)S(6)()()順に構築される。これらもまた 式の終了時に破棄されるのではなく、&& 式の終了時に破棄される。 したがって、S(6)S(5) の破棄は、S(2)S(1) の破棄よりも先に実行される。

カンマ式

CommaExpression:
    AssignExpression
    CommaExpression , AssignExpression

, の左オペランドが評価され、次に右オペランドが評価される。 式の型は右オペランドの型であり、結果は右オペランドの結果である。 カンマ式の結果を使用することはできない。

代入式

AssignExpression:
    ConditionalExpression
    ConditionalExpression = AssignExpression
    ConditionalExpression += AssignExpression
    ConditionalExpression -= AssignExpression
    ConditionalExpression *= AssignExpression
    ConditionalExpression /= AssignExpression
    ConditionalExpression %= AssignExpression
    ConditionalExpression &= AssignExpression
    ConditionalExpression |= AssignExpression
    ConditionalExpression ^= AssignExpression
    ConditionalExpression ~= AssignExpression
    ConditionalExpression <<= AssignExpression
    ConditionalExpression >>= AssignExpression
    ConditionalExpression >>>= AssignExpression
    ConditionalExpression ^^= AssignExpression

すべての代入式において、左オペランドは変更可能な 左辺値でなければならない。代入式の型は左オペランドの型であり、 結果は代入が行われた後の左オペランドの値である。 結果の式は変更可能な左辺値である。

Undefined Behavior: どちらかのオペランドが参照型であり、以下のいずれかに該当する場合、
  1. オペランドの記憶領域が部分的に重複している
  2. オペランドの記憶領域が完全に重複しているが、型が異なる場合
Implementation Defined: どちらのオペランドも参照型ではなく、以下のいずれかに該当する場合:
  1. オペランドの記憶域が部分的に重複している
  2. オペランドの記憶域が完全に重複しているが、型が異なる場合

単純代入式

演算子が= の場合、単純代入である。

そうでない場合は、右オペランドは左オペランドの型に暗黙的に変換され、 それに代入される。

代入演算子式

組み込み型の引数に対する代入演算子式は、

a op= b
意味的には以下と同等である。
a = cast(typeof(a))(a op b)
ただし、

ユーザー定義型の場合、代入演算子式は 二項演算子とは別にオーバーロードされる。 それでも左オペランドはl値でなければならない。

条件式

ConditionalExpression:
    OrOrExpression
    OrOrExpression ? Expression : ConditionalExpression

最初の式はbool に変換され、評価される。

true である場合、2番目の式が評価され、 その結果が条件式の結果となる。

false であれば、3番目の式が評価され、 その結果が条件式の結果となる。

2番目または3番目の式がvoid 型である場合、 結果の型はvoid となる。それ以外の場合、2番目と3番目の 式は暗黙的に共通の型に変換され、これが 条件式の結果の型となる。

注釈: 条件式が代入式の左オペランドである場合、 明確にするために括弧が必要となる。
bool test;
int a, b, c;
...
test ? a = b : c = 2;   // エラー
(test ? a = b : c) = 2; // OK

これにより意図が明確になります。最初の文は、 次のコードと誤読されやすいからです。

test ? a = b : (c = 2);

論理式

See Also: xml-ph-0000@deepl.internal の単項式。
単項式 !expr

OrOr式

OrOrExpression:
    AndAndExpression
    OrOrExpression || AndAndExpression

OrOrExpressionの結果の型はbool である。ただし、右オペランドがvoid 型の場合、結果はvoid 型となる。

OrOrExpressionは左オペランドを評価する。

左オペランドが型bool に変換され、true と評価される場合、 右オペランドは評価されない。OrOrExpressionの結果の型がbool の場合、 式の結果はtrue となる。

左オペランドがfalse の場合、右 オペランドが評価される。 OrOrExpressionの結果の型が bool の場合、 式の結果は右オペランドがbool 型に変換されたものとなる。

そしてそして式

AndAndExpression:
    OrExpression
    AndAndExpression && OrExpression

AndAndExpressionの結果の型はbool である。ただし、右オペランドがvoid 型の場合、結果はvoid 型となる。

AndAndExpressionは左オペランドを評価する。

左オペランドが型bool に変換され、false と評価される場合、 右オペランドは評価されない。AndAndExpressionの結果の型がbool の場合、 式の結果はfalse となる。

左オペランドがtrue の場合、右 オペランドが評価される。 AndAndExpressionの結果の型が bool の場合、式の結果は 右オペランドをbool 型に変換したものとなる。

ビット演算式

ビット単位の式は、 オペランドに対してビット単位の演算を実行する。 オペランドは整数型でなければならない。 まず、通常の算術変換が実行される。次に、ビット単位の 演算が実行される。

注釈:OrExpression 、XorExpressionまたはAndExpressionが EqualExpression 、IdentityExpressionまたはRelExpressionのどちらかの側に現れる場合、 コンパイルエラーとなる。代わりに、括弧を使用して明確化する。
int x, a, b;
x = a & 5 == b; // エラー
x = a & 5 is b; // エラー
x = a & 5 <= b; // エラー

x = (a & 5) == b; // OK
x = a & (5 == b); // OK

または式

OrExpression:
    XorExpression
    OrExpression | XorExpression

オペランドはORで結合される。

Xor式

XorExpression:
    AndExpression
    XorExpression ^ AndExpression

オペランドはXOR演算される。

そして、式

AndExpression:
    CmpExpression
    AndExpression & CmpExpression

オペランドはAND演算で結合される。

式を比較する

CmpExpression:
    EqualExpression
    IdentityExpression
    RelExpression
    InExpression
    ShiftExpression

等式の式

EqualExpression:
    ShiftExpression == ShiftExpression
    ShiftExpression != ShiftExpression

等式は、2つのオペランドを等しい(== )か、 または等しくない(!= )かで比較する。 結果の型はbool である。

不等号は、等号の論理否定として定義される。

オペランドが整数値の場合、 比較の前にそれらを共通の型に変換するために通常の算術変換が適用される。等価性は、 共通の型のビットパターンが完全に一致する

オペランドがポインタの場合、オペランドのビットパターンが完全に一致する場合に等価とみなされる。

float、double、および実数値の場合は、通常の算術変換が適用され、 比較前に共通の型に変換される。 値-0+0 は等しいとみなされる。 どちらか一方または両方のオペランドがNaNの場合、== はfalseを返し、!=true を返す。 それ以外の場合、共通の型のビットパターンが等価であるか比較される。

静的配列および動的配列の場合、等価性は 配列の長さが 一致し、すべての要素が等しい 場合と定義される。

Deprecated:
複素数については、等価性は以下と同等であると定義される。
x.re == y.re && x.im == y.im

クラスと構造体の等価性

構造体オブジェクトの場合、等価性とは opEquals() メンバ関数の結果を意味する。 opEquals() が提供されていない場合、等価性は 対応するオブジェクトフィールドの等価性の 結果の論理積として定義される。

Implementation Defined: 構造体オブジェクト内の整列ギャップの内容。
Best Practices: フィールドが重複している場合、つまり共用体で発生する場合は、デフォルトの 等価性は重複する各フィールドを比較する。 は、重複するフィールドのうち、有効なデータを含むフィールドを特定できる。 は、浮動小数点NaN値のデフォルトの動作を上書きし、 常に不適合として比較する。 を使用して を実装する際は、次の点に注意すること。opEquals() opEquals() memcmp() opEquals()

クラスおよび構造体オブジェクトの場合、式(a == b)は 次のように書き換えられる。 a.opEquals(b) 、また、(a != b)!a.opEquals(b) となる。

クラスオブジェクトの場合、== および!= 演算子はオブジェクトの内容を比較する目的で使用されるが、 これを機能させるには適切なopEquals オーバーライドを定義する必要がある。 ルートクラスであるObject が提供するデフォルトのopEquals は、 is 演算子(下記参照)と同等である。 null との比較は無効である。なぜなら、null には内容がないからだ。 代わりにis および!is 演算子を使用すること。

class C;
C c;
if (c == null)  // エラー
    ...
if (c is null)  // OK
    ...

識別式

IdentityExpression:
    ShiftExpression is ShiftExpression
    ShiftExpression ! is ShiftExpression

is 演算子は、式の値の同一性を比較する。 非同一性を比較するには、e1 !is e2 を使用する。 結果の型はbool である。 被演算数は、比較前に共通の型にするために、通常の算術変換が行われる。

クラス/インターフェイスオブジェクトの場合、同一性はオブジェクト参照が同一であると定義される。 nullクラスオブジェクトはis と比較できる。 インターフェイスオブジェクトは、キャスト元のクラスと同じ参照を持つ必要はないことに注意。 あるinterface が別のinterface /class 値とクラスインスタンスを共有しているかどうかを調べるには、is と比較する前に両方のオペランドをObject にキャストする。

interface I { void g(); }
interface I1 : I { void g1(); }
interface I2 : I { void g2(); }
interface J : I1, I2 { void h(); }

class C : J
{
    override void g() { }
    override void g1() { }
    override void g2() { }
    override void h() { }
}

void main() @safe
{
    C c = new C;
    I i1 = cast(I1) c;
    I i2 = cast(I2) c;
    assert(i1 !is i2); // 同一ではない
    assert(c !is i2); // 同一ではない
    assert(cast(Object) i1 is cast(Object) i2); // 同一である
}

構造体オブジェクトと浮動小数点値については、同一性は 演算子のビットが同一であると定義される。

静的配列と動的配列の場合、2つの配列の同一性は、 両方の配列が同じメモリ位置を参照し、同じ数の要素を含む 場合に与えられる。

Object o;
assert(o is null);

auto a = [1, 2];
assert(a is a[0..$]);
assert(a !is a[0..1]);

auto b = [1, 2];
assert(a !is b);
Deprecated: xml-ph-0000@deepl.internalを使用して静的配列をアドレスと長さで比較することは推奨されない。 代わりにスライス演算子を使用して配列のスライスを比較すること。 例えば、
is を使用して静的配列をアドレスと長さで比較することは推奨されない。 そうする場合は、スライス演算子を使用して配列のスライスを比較する。 例えば、a1[] is a2[]

他のオペランド型については、同一性が等価であると定義される。

同一演算子is はオーバーロードできない。

関係式

RelExpression:
    ShiftExpression < ShiftExpression
    ShiftExpression <= ShiftExpression
    ShiftExpression > ShiftExpression
    ShiftExpression >= ShiftExpression

まず、演算子に対して通常の算術変換が実行される。 関係式の結果の型はbool である。

配列の比較

静的配列および動的配列の場合、CmpExpressionの結果は、 配列の最初の非等しい要素に適用された演算子の結果となる。 2つの配列が等しいと比較されるが、長さが異なる場合、 短い方の配列は長い方の配列よりも「短い」と比較される。

整数の比較

整数比較は、両方のオペランドが整数型である場合に発生する。

整数比較演算子
OperatorRelation
<less
>より大きい
<=以下
>=以上
==等しい
!=等しくない

<<=> 、または>= 式において、一方のオペランドが符号付きで、もう一方が符号なしであるのはエラーである。 キャストを使用して、両方のオペランドを符号付きにするか、両方のオペランドを符号なしにする。

浮動小数点数の比較

どちらか一方または両方のオペランドが浮動小数点の場合は、浮動小数点の 比較が行われる。

CmpExpressionには NaN 個のオペランドを指定できる。 オペランドのいずれか、または両方がNaN の場合、浮動小数点 比較演算は以下のように返される。

浮動小数点比較演算子
OperatorRelationReturns
<lessfalse
>greaterfalse
<=以下false
>=以上false
==等しいfalse
!=順序なし、より小さい、またはより大きいtrue
Best Practices: IdentityExpressionを使用して をチェックすることは可能だが、 実行時に生成される NaN の浮動小数点値には他にもある。 T.nanstd.math.traits.isNaNそれらすべてを処理する。

クラスの比較

クラスオブジェクトの場合、EqualExpressionRelExpressionは オブジェクトの内容を比較する。 したがって、null のクラス参照と比較することは無効である。なぜなら、null には内容がないからだ。

class C {}

void fun()
{
    C c;
    //if (c < null) {}  // コンパイル時エラー
    assert(c is null);
    if (c > new C) {}  // 実行時エラー
}

クラスオブジェクトの場合、Object.opCmp() の結果が左オペランドとなり、0 の結果が右オペランドとなる。 EqualExpressionまたはRelExpression 結果(o1 op o2) は以下のとおりである。

(o1.opCmp(o2) op 0)
emailemail

式では、

InExpression:
    ShiftExpression in ShiftExpression
    ShiftExpression ! in ShiftExpression

連想配列などのコンテナは、 特定のキーが含まれているかどうかをテストすることができる

int foo[string];
...
if ("hello" in foo)
{
    // 文字列が見つかった
}

InExpressionの結果は、連想配列へのポインタとなる。 一致するキーがない場合、ポインタはnull となる。 一致するキーがある場合、ポインタはそのキーに関連付けられた値を指す。

!in 式は、in演算の論理否定である。

in 式は、関係式<<= などと同じ優先順位を持つ。

注釈:inをオーバーロードする場合、通常はopBinaryRight のみが定義される。 これは、 通常はキー型ではなくコンテナによって操作が定義されるためである。コンテナは、in演算子の右辺に表示される。

シフト式

ShiftExpression:
    AddExpression
    ShiftExpression << AddExpression
    ShiftExpression >> AddExpression
    ShiftExpression >>> AddExpression

オペランドは整数型でなければならず、整数拡張が行われる。 結果の型は、拡張後の左オペランドの型となる。 結果の値は、右オペランドの値によってビットがシフトされた結果となる。

Implementation Defined: 負の値によるシフト、またはシフトされる数量のサイズと同じかそれ以上のビットによるシフトの結果は、 未定義である。 シフト量がコンパイル時に既知である場合、このような操作を行うと コンパイルエラーとなる。
int c;

int s = -3;
auto y = c << s; // 実装定義値

auto x = c << 33;  // エラー、許容される最大シフト数は31である

加法式

AddExpression:
    MulExpression
    AddExpression + MulExpression
    AddExpression - MulExpression
    AddExpression ~ MulExpression

加算式

加算演算の場合、+ および- :

オペランドが整数型の場合、それらは通常の算術変換を受け、 その後、通常の算術変換を使用して共通の型に変換される。

両方のオペランドが整数型であり、計算中にオーバーフローまたはアンダーフローが発生した場合は、 丸めが行われる。例えば:

どちらかのオペランドが浮動小数点数型の場合、もう一方は暗黙的に 浮動小数点数に変換され、通常の算術変換によって共通の型に変換される 。

浮動小数点演算子に対する加算式は結合されない。

ポインタの算術演算

最初のオペランドがポインタであり、2番目のオペランドが整数型である場合、 結果の型は最初のオペランドの型となり、結果の 値はポインタに2番目のオペランドを足したもの(または引いたもの)に、 最初のオペランドが指す型のサイズを掛けたものとなる。

int[] a = [1,2,3];
int* p = a.ptr;
assert(*p == 1);

*(p + 2) = 4; // `p[2] = 4`と同じ
assert(a[2] == 4);

IndexOperationはポインタと共に使用することもでき、 整数を加算し、その結果を逆参照するのと同じ動作となる。

第2オペランドがポインタであり、第1オペランドが整数型の場合、 演算子が+ である場合、 オペランドは逆転され、前述のポインタ演算が適用される。

ポインタ算術によるポインタの生成はコードでは許可されていない @safe

両方のオペランドがポインタであり、演算子が+ の場合、 それは不正である。

両方のオペランドがポインタであり、演算子が- の場合、 ポインタが減算され、 その結果がオペランドが指す型のサイズで割られる。 この計算では、void の想定されるサイズは1バイトである。 ポインタが異なる型を指している場合はエラーとなる。 結果の型はptrdiff_t である。

int[] a = [1,2,3];
ptrdiff_t d = &a[2] - a.ptr;
assert(d == 2);

カテゴリ式

加算演算の場合、~ :

CatExpressionはコンテナのデータと他のデータを結合し、 新しいコンテナを生成する。

動的配列の場合、もう一方のオペランドは、別の配列であるか、または 配列の要素型に暗黙的に変換される単一の値でなければならない。 配列の結合を参照。

乗算式

MulExpression:
    UnaryExpression
    MulExpression * UnaryExpression
    MulExpression / UnaryExpression
    MulExpression % UnaryExpression

オペランドは算術型でなければならない。 これらは通常の算術変換を受ける。

整数オペランドの場合、*/%は それぞれ、乗算、除算、剰余演算に対応する。 乗算の場合、オーバーフローは無視され、単に整数型に合うように切り捨てられる。

除算

/ および% 演算子の整数オペランドの場合、 商はゼロに丸められ、余りは 被除数と同じ符号となる。

次の被除数または剰余数:

コンパイル時実行中に検出された場合は、不正です。

Undefined Behavior: 実行時に検出された場合はエラーとなる。 core.checkedint それらをチェックし、定義された動作を選択するために使用できる。

浮動小数点

浮動小数点演算子については、* および/ の演算は IEEE 754 浮動小数点演算の同等演算に相当する。% は IEEE 754 の余りとは異なる。例えば、15.0 % 10.0 == 5.0 であるのに対し、 IEEE 754 ではremainder(15.0,10.0) == -5.0 となる。

浮動小数点オペランドの乗算式は結合性を持たない。

単項式

UnaryExpression:
    & UnaryExpression
    ++ UnaryExpression
    -- UnaryExpression
    * UnaryExpression
    - UnaryExpression
    + UnaryExpression
    ! UnaryExpression
    ComplementExpression
    DeleteExpression
    CastExpression
    ThrowExpression
    PowExpression
OperatorDescription
&l値のメモリアドレスを取得する -ポインタを参照
++使用前にインクリメントする -評価順序を参照
--使用前に減算する
*参照/間接参照 - 通常はポインタに対して
-負の
+
!論理 NOT

単項演算(- および+ )の前に、通常の整数プロモーションが実行される。

補数式

ComplementExpression:
    ~ UnaryExpression

ComplementExpressionsは整数型(bool を除く)で動作する。 値のすべてのビットが補数される。 補数演算の前に通常の整数昇格が行われる。

式を削除する

DeleteExpression:
    delete UnaryExpression
Deprecated: 非推奨となった。代わりに、以下のものを使用すること。
delete 非推奨となりました。代わりに、 destroy 可能であれば、または core.memory.__delete最後の手段としてのみ使用してください。

UnaryExpressionがクラスオブジェクト参照であり、 そのクラスにデストラクタが存在する場合、そのオブジェクトインスタンスに対してデストラクタが 呼び出される。

次に、UnaryExpressionがクラスオブジェクト参照、または 構造体インスタンスへのポインタであり、クラスまたは構造体が "delete" 演算子をオーバーロードしている場合、その演算子は クラスオブジェクトインスタンスまたは構造体インスタンスに対して呼び出される。

そうでない場合は、ガベージコレクタが呼び出され、 クラスインスタンスまたは構造体インスタンスに割り当てられたメモリが即座に解放される。

UnaryExpression がポインタまたは動的配列の場合、 ガベージコレクタが呼び出され、メモリが即座に解放される 。

ポインタ、動的配列、または参照は、削除が実行された後にnullに設定される。 削除後に別の参照を通じてデータを参照しようとすると、 "未定義の動作"となる。

UnaryExpressionがスタック上に割り当てられた変数である場合、 そのインスタンスに対してクラス・デストラクタ(存在する場合)が呼び出される。 ガベージ・コレクタは呼び出されない。

Undefined Behavior:
  1. delete を使用して、ガベージコレクタによって割り当てられていないメモリを解放する。
  2. delete のオペランドであったデータを参照する。

キャスト式

CastExpression:
    cast ( Type ) UnaryExpression
    CastQual

CastExpression は UnaryExpression を "型" に変換する。

cast(foo) -p; // (-p)をfoo型にキャストする
(foo) - p;      // fooからpを引く

基本データ型

基本型に対する暗黙の変換が 実行できない状況では、型システムはキャストを使用して メモリ領域の再解釈を受け入れることを強制される場合がある。

このような状況の例としては、より広い型をより狭い型に格納しようとする場合が挙げられる。

int a;
byte b = a; // int型の式aを暗黙的にbyte型に変換することはできない

キャスト元の型がキャスト先の型よりも大きい場合、 値はキャスト先のサイズに合わせて切り捨てられる。

int a = 64389; // 00000000 00000000 11111011 10000101
byte b = cast(byte) a;       // 10000101
ubyte c = cast(ubyte) a;     // 10000101
short d = cast(short) a;     // 11111011 10000101
ushort e = cast(ushort) a;   // 11111011 10000101

writeln(b);
writeln(c);
writeln(d);
writeln(e);

整数の型では、狭い型から広い型へのキャストは、 符号拡張を行うことで実行される。

ubyte a = 133;  // 10000101
byte b = a;     // 10000101

writeln(a);
writeln(b);

ushort c = a;   // 00000000 10000101
short d = b;    // 11111111 10000101

writeln(c);
writeln(d);

クラス参照

クラス参照を派生クラス参照にキャストする場合は、 実行時にチェックを行い、それが 本当にダウンキャストであることを確認する。そうでない場合は、null が結果として返される。

class A {}
class B : A {}

void main()
{
    A a = new A;
    //B b = a;         // エラー、キャストが必要
    B b = cast(B) a; // aがBでない場合、bはnullである
    assert(b is null);

    a = b;         // キャストは必要ない
    a = cast(A) b; // アップキャストの実行時チェックは必要ない
    assert(a is b);
}

B オブジェクトo がクラスのインスタンスであるかどうかを判断するには 、キャストを使用する。

if (cast(B) o)
{
    // oはBのインスタンスである
}
else
{
    // oはBのインスタンスではない
}

ポインタ型をクラス型にキャストしたり、クラス型をポインタ型にキャストしたりするには、型ペイント( すなわち再解釈キャスト)として行う。

ポインタ

ポインタ変数を別のポインタ型にキャストすると、 ポインタの参照解除の結果として取得される値が変更され、ポインタ演算が実行されるバイト数も 変更される。

int val = 25185; // 00000000 00000000 01100010 01100001
char *ch = cast(char*)(&val);

writeln(*ch);    // a
writeln(cast(int)(*ch)); // 97
writeln(*(ch + 1));  // b
writeln(cast(int)(*(ch + 1)));   // 98

同様に、動的に割り当てられた配列をより小さいサイズの型にキャストする場合、 初期の配列のバイトは、新しい次元に従って分割され、再グループ化される。

import core.stdc.stdlib;

int *p = cast(int*) malloc(5 * int.sizeof);
for (int i = 0; i < 5; i++) {
    p[i] = i + 'a';
}
// p = [97, 98, 99, 100, 101]

char* c = cast(char*) p;     // c = [97, 0, 0, 0, 98, 0, 0, 0, 99 ...]
for (int i = 0; i < 5 * int.sizeof; i++) {
    writeln(c[i]);
}

A型のポインタをB型のポインタにキャストし、B型がA型よりも広い場合、 Aのサイズを超えるメモリにアクセスしようとすると、動作が未定義となる。

char c = 'a';
int *p = cast(int*) (&c);
writeln(*p);

また、基本データ型へのポインタのキャストも可能である。 一般的な方法としては、ポインタをint値にキャストし、 そのアドレスを表示する、というものがある。

import core.stdc.stdlib;

int *p = cast(int*) malloc(int.sizeof);
int a = cast(int) p;
writeln(a);

配列

動的配列を別の動的配列にキャストすることは、 配列の長さと要素サイズを掛けた値が一致する場合のみ可能である。キャストは 型変換として行われ、配列の長さは要素サイズの変更に合わせて調整される。 一致しない場合は、実行時エラーが発生する。

byte[] a = [1,2,3];
//auto b = cast(int[])a; // 実行時エラー: 配列キャストのずれ

int[] c = [1, 2, 3];
auto d = cast(byte[])c; // OK
// 以下のように表示される:
// [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]
writeln(d);

静的配列

静的配列を別の静的配列にキャストすることは、 配列の長さと要素サイズの積が一致する場合のみ可能であり、不一致の場合は 違法となる。 キャストは型ペイント(再解釈キャストとも呼ばれる)として実行される。 配列の内容は変更されない。

byte[16] b = 3; // 各要素を3に設定する
assert(b[0] == 0x03);
int[4] ia = cast(int[4]) b;
// 要素を16進数で表示する
foreach (i; ia)
    writefln("%x", i);
/* prints:
   3030303
   3030303
   3030303
   3030303
 */

整数

整数をより小さい整数にキャストすると、 値は最下位ビットの方向に切り捨てられる。 ターゲットの型が符号付きで、切り捨て後に最上位ビットがセットされる場合、 そのビットは値から失われ、 符号ビットがセットされる。

uint a = 260;
auto b = cast(ubyte) a;
assert(b == 4); // 260 & 0xffのように切り捨てられる

int c = 128;
assert(cast(byte)c == -128); // 再解釈される

符号付き型と符号なし型の間で変換を行う場合、 変換先の型が変換元の値を表現できない場合は、値が再解釈される。

short c = -1;
ushort d = c;
assert(d == ushort.max);
assert(uint(c) == uint.max);

ubyte e = 255;
byte f = e;
assert(f == -1); // 再解釈される
assert(short(e) == 255); // 変更なし

浮動小数点数

浮動小数点リテラルをある型から別の型にキャストすると 型が変更されるが、内部的には定数圧縮の目的で完全な精度が保持される 。

void test()
{
    real a = 3.40483L;
    real b;
    b = 3.40483;     // リテラルを倍精度に切り捨てない
    assert(a == b);
    assert(a == 3.40483);
    assert(a == 3.40483L);
    assert(a == 3.40483F);
    double d = 3.40483; // 変数に代入されたときにリテラルを切り捨てる
    assert(d != a);     // もはや同じではない
    const double x = 3.40483; // constへの代入は切り捨てられない
    assert(x == a);     // 初期化子が見えている場合は切り捨てられる
}

浮動小数点値を整数型にキャストすることは、 切り捨てによる整数への変換と同等である。浮動小数点 値が整数型の範囲外である場合、キャストは 無効な結果を生成する(これはC、C++でも同様である)。

void main()
{
    int a = cast(int) 0.8f;
    assert(a == 0);
    long b = cast(long) 1.5;
    assert(b == 1L);
    long c = cast(long) -1.5;
    assert(c == -1);

    // floatがオーバーフローした場合、キャストは以下の整数値を返却する。
    // 80000000_00000000H(64ビットオペランド)または80000000H(32ビットオペランド)。
    long d = cast(long) float.max;
    assert(d == long.min);
    int e = cast(int) (1234.5 + int.max);
    assert(e == int.min);

    // 16ビットまたは8ビットで表現される型の場合、
    // 結果は32ビット型と同じだが、最上位ビットは無視される。
    short f = cast(short) float.max;
    assert(f == 0);
}

構造体

値 v を構造体 S にキャストする場合、値が 同じ型の構造体でない場合、これは以下と同等である。

S(v)

修飾子キャスト

CastQual:
    cast ( TypeCtorsopt ) UnaryExpression

A CastQual は UnaryExpression の型における修飾子を置き換える。

shared int x;
static assert(is(typeof(cast(const)x) == const int));

型または修飾子を指定せずにキャストすると、constimmutablesharedinoutのいずれかの最上位レベルの型修飾子が UnaryExpressionの型から削除される。

shared int x;
static assert(is(typeof(cast()x) == int));

キャストするvoid

式をvoid 型にキャストすることは、 結果が使用されていないことを示すために許可されている。ExpressionStatementでは、 「効果がない」というエラーを回避するために適切に使用できる。

void foo(lazy void exp) {}
void main()
{
    foo(10);            // NG - 式'10'は何の効果もない
    foo(cast(void)10);  // OK
}

スロー式

ThrowExpression:
    throw AssignExpression

AssignExpressionは評価され、ThrowableまたはThrowable から派生したクラスへの参照を生成しなければならない。 この参照は例外としてスローされ、 現在の制御フローを中断して、try-statementの適切なcatch 節で処理が継続される。このプロセスでは、 該当するtry ブロックに入ってから渡されたすべてのscope (exit) /scope (failure)が 実行される。

throw new Exception("message");

Throwable は、immutableconstinout 、またはshared として修飾されてはならない。 実行時では、スローされたオブジェクトを変更することがあり(例えば、スタックトレースを含めるなど)、 これはconst またはimmutable オブジェクトに違反する可能性がある。

ThrowExpression は別の式の中にネストすることができる。

void foo(int function() f) {}

void main() {
    foo(() => throw new Exception());
}

ThrowExpressionの型は noreturn

Best Practices: プログラムのバグを報告し プログラムを中断するには、ErrorではなくAssert Expressionsを使用する。

べき乗式

PowExpression:
    PostfixExpression
    PostfixExpression ^^ UnaryExpression

PowExpressionは、左オペランドを右オペランドの累乗まで上げる。

Postfix Expressions

PostfixExpression:
    PrimaryExpression
    PostfixExpression . Identifier
    PostfixExpression . TemplateInstance
    PostfixExpression . NewExpression
    PostfixExpression ++
    PostfixExpression --
    PostfixExpression ( NamedArgumentListopt )
    TypeCtorsopt BasicType ( NamedArgumentListopt )
    PostfixExpression IndexOperation
    PostfixExpression SliceOperation
OperationDescription
. 識別子 いずれか:
  • 型または式のプロパティにアクセスする。
  • モジュール、パッケージ、集約型、インスタンス、列挙型、またはテンプレート・インスタンスのメンバにアクセスする。 または
  • UFCSを使用してフリー関数を呼び出す。
. NewExpression ネストされたクラスのインスタンス化
++使用後にインクリメント -評価順を参照
--使用後にデクリメントする
(args) いずれか:
  • オプション引数付きの式を呼び出す
  • オプション引数付きの型を構築する
IndexOperation単一要素の選択
スライス操作一連の要素を選択する

ポストフィックス引数リスト

ArgumentList:
    AssignExpression
    AssignExpression ,
    AssignExpression , ArgumentList
NamedArgumentList: NamedArgument NamedArgument , NamedArgument , NamedArgumentList
NamedArgument: Identifier : AssignExpression AssignExpression

呼び出し可能な式は、括弧で囲まれた名前付き引数のリストの前に置くことができる。 次の式を呼び出すことができる。

xml-ph-0000@deepl.internal
void f(int, int);

void g()
{
    f(5, 6);
    (&f)(5, 6);
}

引数とパラメータの一致

NamedArgumentList 内の引数は、関数パラメータに次のように対応付けられる。

  1. 最初の引数に名前がない場合は、最初の関数パラメータに割り当てられる。
  2. 名前付き引数は、同じ名前の関数パラメータに割り当てられる。 そのようなパラメータが存在しない場合はエラーとなる。
  3. 名前のない引数は、前の引数のパラメータに関連する次のパラメータに割り当てられる。 そのようなパラメータが存在しない場合はエラーとなる。すなわち、前の引数が最後のパラメータに割り当てられている場合などである。
  4. パラメータを複数回割り当てることはエラーである。
  5. パラメータに値を代入しないこともエラーであるが、 ただし、パラメータにデフォルト引数がある場合はこの限りではない。

引数リストで型を構築する

型は引数のリストの前に置くことができる。参照:

インデックス操作

IndexOperation:
    [ ArgumentList ]

基本の PostfixExpressionが評価される。 特別な変数$ が宣言され、 基本の PostfixExpression の要素数(利用可能な場合)に設定される。 ArgumentList の評価用に新しい宣言スコープが作成され、 $ がそのスコープのみに表示される。

PostfixExpression が静的配列型または動的配列型の式である場合、 添字指定の結果は、配列の i 番目の要素の"l値" となる。ここで、iArgumentList から評価された整数である。 PostfixExpressionがポインタである場合、p 、結果は *(p + i) となる(「ポインタ演算」を参照)。

ベースの PostfixExpressionValueSeq の場合 、ArgumentListは1つの引数のみで構成されなければならず、 静的に整数の定数として評価可能でなければならない。 その整数の定数 n はValueSeq の n 番目の式を選択し、これは IndexOperation の結果である。 n が ValueSeq の範囲外の場合はエラーとなる。

インデックス演算子はオーバーロードすることができるArgumentListで複数のインデックスを使用することは、演算子オーバーロードの場合のみサポートされる。

スライス操作

SliceOperation:
    [ ]
    [ Slice ,opt ]
Slice: AssignExpression AssignExpression , Slice AssignExpression .. AssignExpression AssignExpression .. AssignExpression , Slice

PostfixExpressionの基本部分が評価される。 特別な変数$ が宣言され、 PostfixExpressionの要素数(利用可能な場合)に設定される。 AssignExpressionの評価用に、新しい宣言スコープが作成される ..AssignExpression$ は そのスコープのみに表示される。

PostfixExpression のベースが静的または動的配列の場合 a 、スライスの結果は、 a[i] からa[j-1] までの要素を参照する動的配列となる。ここで、i およびj は、それぞれ 最初の AssignExpressionおよび 2 番目の AssignExpressionから評価された整数である。

PostfixExpressionのベースがポインタの場合、pp[i] からp[j-1]までの要素を参照する動的配列が結果として返される。ここで、ij は、 それぞれ最初のAssignExpressionと2番目のAssignExpressionから評価された整数である。

PostfixExpressionのベース がValueSeqの場合、 スライスの結果は、 上限と下限から形成される新しいValueSeqとなり、 静的に整数の定数として評価されなければならない。 これらの範囲が範囲外の場合はエラーとなる。

最初のAssignExpressionは、スライスの下限値(含む)と見なされ 、2番目の AssignExpression は 上限値(含まない)と見なされる。 式の結果は、PostfixExpression の要素のスライスとなる。

[ ] 形式が使用された場合、スライスはベースPostfixExpression内のすべての要素となる。 ベース式はポインタにすることはできない。

スライス演算子はオーバーロードすることができる複数のスライスを使用することは、演算子オーバーロードの場合のみサポートされる 。

SliceOperationは変更不可の"l値"ではない。

スライス変換を静的配列に

スライスの境界がコンパイル時に判明する場合は、スライス式は 静的配列の左辺値に暗黙的に変換できる可能性がある。例えば:

arr[a .. b]     // typed T[]

ab の両方が整数(定数展開される可能性がある)である場合、 スライス式はT[b - a] 型の静的配列に変換できる。

注釈: 静的配列は、長さが一致するかどうかを実行時に確認しながら 、スライスから代入することもできる
void f(int[2] sa) {}

int[] arr = [1, 2, 3];

void test()
{
    //f(arr); // エラー、変換できない
    f(arr[1 .. 3]); // OK
    //f(arr[0 .. 3]); // エラー

    int[2] g() { return arr[0 .. 2]; }
}
void bar(ref int[2] a)
{
    assert(a == [2, 3]);
    a = [4, 5];
}

void main()
{
    int[] arr = [1, 2, 3];

    // lvalueをスライスするとlvalueが得られる
    bar(arr[1 .. 3]);
    assert(arr == [1, 4, 5]);
}

主要な式

PrimaryExpression:
    Identifier
    . Identifier
    TemplateInstance
    . TemplateInstance
    $
    LiteralExpression
    AssertExpression
    MixinExpression
    ImportExpression
    NewExpression
    FundamentalType . Identifier
    TypeCtoropt ( Type ) . Identifier
    ( Type ) . TemplateInstance
    FundamentalType ( NamedArgumentListopt )
    TypeCtoropt ( Type ) ( NamedArgumentListopt )
    Typeof
    TypeidExpression
    IsExpression
    ( Expression )
    SpecialKeyword
    TraitsExpression
LiteralExpression: this super null true false IntegerLiteral FloatLiteral CharacterLiteral StringLiteral InterpolationExpressionSequence ArrayLiteral AssocArrayLiteral FunctionLiteral
ExpressionDescription
. 識別子 モジュールスコープ演算子
$ インデックス化/スライスされるオブジェクトの要素数。
( ). 識別子 型プロパティまたは 型の静的メンバにアクセスする。
FundamentalType (arg) オプション引数を持つスカラー型の 均一な構造
( )(args) オプション引数を持つ型を構築する。
( )式を評価する -部分式として便利である。

これ

コンストラクタまたは非staticメンバ関数内では、this は 関数が呼び出されたオブジェクトへの参照として解決される。

typeof(this)は、 複合型定義内のどこでも有効である。 クラスメンバ関数が明示的な参照とともに呼び出される場合 typeof(this) 、非仮想関数が呼び出される。

class A
{
    char get() { return 'A'; }

    char foo() { return typeof(this).get(); } // `A.get`を呼び出す
    char bar() { return this.get(); } // 動的、単なる`get()`と同じ
}

class B : A
{
    override char get() { return 'B'; }
}

void main()
{
    B b = new B();

    assert(b.foo() == 'A');
    assert(b.bar() == 'B');
}

this への割り当てはクラスには許可されていない。

参照:

super

super this と同一であるが、 の基底クラスにキャストされる点が異なる。 基底クラスが存在しない場合はエラーとなる。 ( クラスで基底クラスを持たないのは だけであるが、 クラスは指定しない限り基底クラスを持たないことに注意。) メンバ関数が明示的に への参照で呼び出された場合、 this extern(D) Object extern(C++) super

super への代入は許可されていない。

参照:基本クラスの構築

null

null ポインタ、関数へのポインタ、デリゲート、 ポインタ、関数へのポインタ、デリゲート、 ダイナミック配列、連想配列、 クラスオブジェクトの null値を表す。型にキャストされていない場合、 単一型である が割り当てられ、 ポインタ、関数へのポインタ、デリゲートなどのnull値への正確な変換となる。 型にキャストされた後は、このような変換は暗黙的になるが、 正確ではなくなる。 typeof(null)

文字列リテラル

StringLiteral文法を参照。

文字列リテラルは読み取り専用である。 文字列後置詞を伴わない文字列リテラルは、 暗黙的に以下のいずれかの型に変換できる。 これらは同等に扱われる。 xml-ph-0000@deepl.internal

immutable(char)*
immutable(wchar)*
immutable(dchar)*
immutable(char)[]
immutable(wchar)[]
immutable(dchar)[]
Undefined Behavior: 文字列リテラルへの書き込み。これは コードでは許可されない。@safe

デフォルトでは、文字列リテラルは動的配列として型付けされるが、要素 数はコンパイル時に判明している。そのため、すべての文字列リテラルは 暗黙のうちに不変の静的配列に変換される。

void foo(char[2] a)
{
    assert(a[0] == 'b');
}
void bar(ref const char[2] a)
{
    assert(a == "bc");
}

void main()
{
    foo("bc");
    foo("b"); // OK
    //foo("bcd"); // エラー、文字数が多すぎる
    bar("bc"); // OK、同じ長さ
    //bar("b"); // エラー、長さが一致しなければならない
}

文字列リテラルは、同じ長さまたはそれより長い静的配列の右辺値に変換される。 余分な要素はゼロで埋められる。文字列リテラルは 同じ長さの静的配列の左辺値にも変換できる。

文字列リテラルには'\0' が付加されており、 これにより、ヌル文字で終端するconst char* 文字列を期待する C または C++ 関数に簡単に渡すことができる。 '\0' は文字列リテラルの.length プロパティには含まれない。

文字列リテラルの連結には、 ~ 演算子を使用する必要があり、コンパイル時に解決される。 演算子を介さない"C言語のスタイル"の暗黙的な連結は エラーが発生しやすく、Dではサポートされていない。

styleスタイル

16進文字列リテラル

16進文字列リテラルはテキストデータに限らないバイナリデータを含むため、他の文字列リテラルよりもさらに多くの変換が可能である。

16進文字列リテラルは、暗黙的に定数byte[] またはubyte[] に変換される。

xml-ph-0000@deepl.internal
immutable ubyte[] b = x"3F 80 00 00";
const byte[] c = x"3F 80 00 00";

1より大きなサイズの整数配列に明示的にキャストできる16進文字列リテラル。 16進文字列ではビッグエンディアンバイト順が想定される。

static immutable uint[] data = cast(immutable uint[]) x"AABBCCDD";
static assert(data[0] == 0xAABBCCDD);

これは、16進文字列の長さが配列要素のバイトサイズの倍数であることを必要とする。

xml-ph-0000@deepl.internal
static e = cast(immutable ushort[]) x"AA BB CC";
// エラー、3バイトの長さは2の倍数ではない、`ushort`のサイズ

16進文字列リテラルが定数展開されると、結果はもはや16進文字列リテラルとはみなされない

static immutable byte[] b = x"AA" ~ "G"; // エラー: `string`を`immutable byte[]`に変換できない

配列リテラル

ArrayLiteral:
    [ ArrayMemberInitializationsopt ]
ArrayMemberInitializations: ArrayMemberInitialization ArrayMemberInitialization , ArrayMemberInitialization , ArrayMemberInitializations
ArrayMemberInitialization: NonVoidInitializer AssignExpression : NonVoidInitializer

配列リテラルとは、角カッコ[] の間にカンマで区切って並べた式のリストである。 これらの式は動的配列の要素となる。 配列の長さは要素の数である。

配列の要素型は、すべての要素の共通型として推論され、 各式は暗黙的にその型に変換される。 配列の型が指定されている場合、リテラルの要素は 暗黙的に指定された要素型に変換される。

auto a1 = [1, 2, 3];   // 型はint[]で、要素は1、2、3である
auto a2 = [1u, 2, 3];  // 型はuint[]で、要素は1u、2u、3uである
byte[] a3 = [1, 2, 3]; // OK
byte[] a4 = [128];     // エラー
デフォルトでは、配列リテラルは動的配列として型付けされるが、要素 数はコンパイル時に既知である。したがって、配列リテラルは 暗黙的に同じ長さの静的配列に変換される。
int[2] sa = [1, 2]; // OK
int[2] sb = [1];    // エラー
注釈: スライス長が静的に既知の動的配列をスライスすることも、 静的配列への変換を可能にする
xml-ph-0000@deepl.internal

ArrayMemberInitializationValueSeq の場合、 ValueSeq の要素は シーケンスの代わりに式として挿入される。

配列リテラルはメモリ管理ヒープに割り当てられる。 したがって、関数から安全に返すことができる。

int[] foo()
{
    return [1, 2, 3];
}

特定のインデックスの要素を初期化するには、 AssignExpression : NonVoidInitializer構文を使用する。 AssignExpressionはコンパイル時に指定する必要がある。 欠落している要素はすべて、要素型のデフォルト値に初期化される。 配列型が指定されていない場合、リテラルは 連想配列として解析される ことに注意すること。

int n = 4;
auto aa = [0:1, 3:n]; // 連想配列`int[int]`

int[] a = [1, 3:n, 5];
assert(a == [1, 0, 0, n, 5]);

//int[] e = [n:2]; // エラー、コンパイル時にnがわからない

キャスト

配列リテラルが別の配列型にキャストされる場合、 配列の各要素は新しい要素型にキャストされる。 リテラルではない配列がキャストされる場合、配列は 新しい型として再解釈され、長さが再計算される。

// 配列リテラルをキャストする
const ubyte[] ct = cast(ubyte[]) [257, 257];
// これは等価である:
// const ubyte[] ct = [cast(ubyte) 257, cast(ubyte) 257];
writeln(ct);  // [1, 1]を書き込む

// 他の配列式をキャストする
// --> CastExpressionの通常の動作
byte[] arr = [1, 1];
short[] rt = cast(short[]) arr;
writeln(rt);  // [257]を書き込む
つまり、配列リテラルをキャストすると、各初期化要素の型が変更される。
Best Practices: 要素が暗黙的に期待される型に変換できる場合は、配列リテラルのキャストは避けるべきである。 その代わりに、その型の変数を宣言し、 配列リテラルで初期化する。 暗黙的な変換よりもキャストの方がバグが発生しやすい。
array literal配列リテラル

連想配列リテラル

AssocArrayLiteral:
    [ KeyValuePairs ]
KeyValuePairs: KeyValuePair KeyValuePair , KeyValuePairs
KeyValuePair: KeyExpression : ValueExpression
KeyExpression: AssignExpression
ValueExpression: AssignExpression

連想配列リテラルは、 キーと:値のペアを 角カッコ[] で囲み、カンマで区切った リストである。このリストは空であってはならない。 すべてのキーの共通型は、連想配列のキー型と見なされ、 すべてのキーは暗黙的にその型に変換される。 すべての値の共通型は、連想配列の値型と見なされ、 すべての値は暗黙的にその型に変換される 。 連想配列リテラルは、静的に初期化する目的では使用できない 。

[21u: "he", 38: "ho", 2: "hi"]; // 型はstring[uint]
                              // キーは21u, 38u, 2u
                              // 値は "he", "ho", "hi"

KeyValuePairsのキーまたは値のいずれかが ValueSeq の場合、その ValueSeq の要素は 配列の代わりに引数として挿入される。

連想配列の初期化子には重複するキーを含めることができるが、 その場合は最後に辞書順で遭遇したKeyValuePair が 格納される。

auto aa = [21: "he", 38: "ho", 2: "hi", 2:"bye"];
assert(aa[2] == "bye")

関数リテラル

FunctionLiteral:
    function RefOrAutoRefopt Typeopt ParameterWithAttributesopt FunctionLiteralBody2
    delegate RefOrAutoRefopt Typeopt ParameterWithMemberAttributesopt FunctionLiteralBody2
    RefOrAutoRefopt ParameterWithMemberAttributes FunctionLiteralBody2
    BlockStatement
    Identifier => AssignExpression
ParameterWithAttributes: Parameters FunctionAttributesopt
ParameterWithMemberAttributes: Parameters MemberFunctionAttributesopt
FunctionLiteralBody2: => AssignExpression SpecifiedFunctionBody
RefOrAutoRef: ref auto ref

関数リテラルは、匿名関数 および匿名デリゲートを式に直接埋め込むことを可能にする。 短い関数リテラルはラムダとして知られている。

例えば:

int function(char c) fp; // 関数へのポインタを宣言する

void test()
{
    static int foo(char c) { return 6; }

    fp = &foo;
}
は、次のものとまったく同等である。
int function(char c) fp;

void test()
{
    fp = function int(char c) { return 6; };
}

FunctionLiteralBody2が囲み関数の非静的ローカル変数にアクセスする場合は、デリゲートが必要である。

は、次のコードとまったく同じである。
int abc(int delegate(int i));

void test()
{
    int b = 3;
    int foo(int c) { return 6 + b; }

    abc(&foo);
}
は、次のコードとまったく同じである。
int abc(int delegate(int i));

void test()
{
    int b = 3;

    abc( delegate int(int c) { return 6 + b; } );
}

ref の使用は、戻り値が参照によって返されることを宣言する。

void main()
{
    int x;
    auto dg = delegate ref int() { return x; };
    dg() = 3;
    assert(x == 3);
}
注釈:ネストした関数と関数リテラルを比較する場合、function 形式は静的 または非ネスト関数に類似しており、delegate 形式は 非静的ネスト関数に類似している。すなわち、 デリゲートリテラルは、囲む関数の非静的ローカル変数にアクセスできるが、 関数リテラルはできない。

デリゲート推論

リテラルがfunction またはdelegate を省略しており、 文脈から想定される型がない場合、 それが囲む関数内の変数にアクセスしている場合はデリゲートと推測され、 そうでない場合は関数ポインタとなる。

void test()
{
    int b = 3;

    auto fp = (uint c) { return c * 2; }; // 関数ポインタとして推論される
    auto dg = (int c) { return 6 + b; }; // デリゲートとして推論される

    static assert(!is(typeof(fp) == delegate));
    static assert(is(typeof(dg) == delegate));
}

デリゲートが想定されている場合、リテラルは、 たとえそれが囲む関数の変数にアクセスしていなくても、デリゲートとして推論される。

void abc(int delegate(int i)) {}
void def(uint function(uint s)) {}

void test()
{
    int b = 3;

    abc( (int c) { return 6 + b; } );  // デリゲートとして推論される
    abc( (int c) { return c * 2; } );  // デリゲートとして推論される

    def( (uint c) { return c * 2; } ); // 関数として推論される
    //def( (uint c) { return c * b; } );  // エラー!
    // FunctionLiteralはbにアクセスしているため、その型はデリゲートと推論される。
    // しかし、defはデリゲート引数を受け取ることができない。
}

パラメータの型推論

関数リテラルの型がそのコンテキストから一意に決定できる場合、 パラメータの型推論が可能である。

void foo(int function(int) fp);

void test()
{
    int function(int) fp = (n) { return n * 2; };
    // パラメータnの型はintと推測される。

    foo((n) { return n * 2; });
    // パラメータnの型はintと推測される。
}
xml-ph-0000@deepl.internal
auto fp = (i) { return 1; }; // エラー、`i`の型を推論できない

関数リテラルエイリアス

関数リテラルはエイリアス化できる。 未指定のパラメータ型を持つ関数リテラルをエイリアス化すると、 関数テンプレートが 生成され、リテラルの未指定のパラメータ型ごとに型パラメータが指定される。 リテラルの型推論は、テンプレートがインスタンス化されたときに実行される。

alias fpt = (i) { return i; }; // OK、`i`の型を推論する
//auto fpt(T)(T i) { return i; } // 等価である

auto v = fpt(4);    // `i`はintと推論される
auto d = fpt(10.3); // `i`はdoubleと推論される

alias fp = fpt!float;
auto f = fp(0); // fはfloatである

戻り値の型推論

FunctionLiteralの戻り値の型は、 AssignExpression、または BlockStatement内の ReturnStatementsのいずれかから 推論できる。コンテキストから期待される型が異なり、 最初に推論された戻り値の型が暗黙的に期待される型に変換される場合、 戻り値の型は期待される型として推論される。

auto fi = (int i) { return i; };
static assert(is(typeof(fi(5)) == int));

long function(int) fl = (int i) { return i; };
static assert(is(typeof(fl(5)) == long));

短縮構文(nullary)

BlockStatement関数本体がある場合、関数リテラルではパラメータを完全に省略できる。

注釈: この形式は、ExpressionStatementとして即座に呼び出すことはできない。 これは、BlockStatementと区別するために任意の先読みが必要となるためである。
auto f = { writeln("hi"); }; // OK、fは`void function()`型である
f();
{ writeln("hi"); }(); // エラー
() { writeln("hi"); }(); // OK
匿名のデリゲートは任意の文リテラルのように振る舞うことができる。 例えば、以下では任意の文がループによって実行される。
void loop(int n, void delegate() statement)
{
    foreach (_; 0 .. n)
    {
        statement();
    }
}

void main()
{
    int n = 0;

    loop(5, { n += 1; });
    assert(n == 5);
}
xml-ph-0000@deepl.internal

短縮されたボディの構文

=> AssignExpression の構文は、{ return AssignExpression; } と同等である。

void main()
{
    auto i = 3;
    auto twice = function (int x) => x * 2;
    assert(twice(i) == 6);

    auto square = delegate () => i * i;
    assert(square() == 9);

    auto n = 5;
    auto mul_n = (int x) => x * n;
    assert(mul_n(i) == 15);
}

構文Identifier => AssignExpression(Identifier) { return AssignExpression; } と同等である。

// 次の2つの宣言は等価である
alias fp = i => 1;
alias fp = (i) { return 1; };
Best Practices: 関数リテラルの最小形式は、 テンプレートエイリアスパラメータの引数として最も有用である。
int motor(alias fp)(int i)
{
    return fp(i) + 1;
}

int engine()
{
    return motor!(i => i * 2)(6); // 返却値 13
}
xml-ph-0000@deepl.internal
注釈:Identifier { statement; } の構文はサポートされていない。 セミコロンが誤って省略された場合、 x = Identifier; { statement; }; の文と混同されやすいためである。
xml-ph-0001@deepl.internalxml-ph-0001@deepl.internal

組み込みのスカラー型に対する統一された構文

組み込みのスカラー型の暗黙の変換は、 関数呼び出し構文を使用することで明示的に表現できる。例えば:

auto a = short(1);  // 暗黙のうちに整数リテラル'1'をshortに変換する
auto b = double(a); // 暗黙的にshort変数'a'をdoubleに変換する
auto c = byte(128); // エラー、128はバイトでは表現できない

引数が省略された場合、スカラー型のデフォルトの構築を意味する。

auto a = ushort();  // ushort.initと同じ
auto b = wchar();   // wchar.initと同じ

引数に名前を付けることはできない。

auto a = short(x: 1); // エラー

参照:通常の算術変換

arithmetic conversion算術変換

式を主張する

AssertExpression:
    assert ( AssertArguments )
AssertArguments: AssignExpression ,opt AssignExpression , AssignExpression ,opt

最初のAssignExpressionが評価され、ブール値に変換される。 値がtrue でない場合、アサートエラーが発生し、 プログラムは無効な状態に入る。

int i = fun();
assert(i > 0);

AssertExpressionは、それが unittestまたはin 契約

最初の AssignExpressionが、 クラス不変が存在するクラスのインスタンスへの参照である場合、 クラス不変は保持されなければならない。

最初の AssignExpressionが構造体インスタンスへのポインタであり、 その構造体インスタンスに対して 構造体インバリアントが存在する場合、構造体インバリアントを保持しなければならない。

AssertExpressionの型はvoid である。

Undefined Behavior: 無効な状態に陥った場合、プログラムの実行継続時の動作は 未定義となる。
Implementation Defined: 最初の AssertExpressionが評価されるかどうか (実行時)は、通常、コンパイラのスイッチで設定される。評価されない場合、 AssertExpression で指定されたあらゆる副作用が発生しない可能性がある。 最初の AssertExpressionが評価された場合の動作( )も 通常、コンパイラのスイッチで設定され、以下のオプションが含まれる可能性がある。 false
  1. 特別なCPU命令の実行により即座に停止する
  2. プログラムを中断する
  3. 対応する C ランタイムライブラリ内の assert 失敗関数を呼び出す
  4. DランタイムライブラリでAssertError 例外をスローする
xml-ph-0000@deepl.internal
注釈:AssertError のスローは、dmd のデフォルトであり、 -checkaction=context 最初の AssertExpressionで使用された特定のサブ式をエラーメッセージに表示するオプションのスイッチがある。
auto x = 4;
assert(x < 3);
使用時には、上記のコードはAssertError4 >= 3 というメッセージとともにスローする。
Best Practices: AssignExpressionのどちらにも副作用はない。その後のコードが 依存している。
  1. AssignExpression のいずれにおいても、その後のコードに依存する副作用は発生しない 。
  2. アサート式はプログラムのバグを検出することを目的としている。 入力エラーや環境エラーの検出には使用しないこと。
  3. アサートエラー発生後に通常の実行を再開しようとしてはならない。
xml-ph-0000@deepl.internal

コンパイル時の評価

最初の AssignExpression がすべてコンパイル時の定数で構成され、false と評価される場合は、特別なケースであり、 その後の文は到達不能コードであることを意味する。 コンパイル時関数実行(CTFE)は試行されない。

最初の AssignExpressionがコンパイル時にfalseと評価される場合、実装では異なる処理が行われる可能性がある。 他のassertが無視される場合でも、HLT 命令または同等の命令が生成される可能性がある。

関連項目: static assert

メッセージをアサートする

2番目のAssignExpression が存在する場合、暗黙的にconst(char)[] 型に変換できる必要がある。 これが存在する場合、実装ではこれを評価し、 アサートが失敗した際に結果のメッセージを表示できる。

xml-ph-0000@deepl.internal
void main()
{
    assert(0, "an" ~ " error message");
}

コンパイルして実行すると、以下のメッセージが表示される。

core.exception.AssertError@test.d(3) an error message
0email
xml-ph-0000@deepl.internalxml-ph-0000@deepl.internal

ミックスイン式

MixinExpression:
    mixin ( ArgumentList )

ArgumentList内の 各AssignExpressionは コンパイル時に評価され、結果は文字列として表現できるものでなければならない。 結果の文字列は結合されて1つの文字列が形成される。 文字列のテキスト内容は、有効な式としてコンパイル可能なものでなければならず、 そのようにコンパイルされる。

int foo(int x)
{
    return mixin("x +", 1) * 7;  // ((x + 1) * 7)と同じ
}

式をインポートする

ImportExpression:
    import ( AssignExpression )

AssignExpression は、コンパイル時に 定数文字列として評価されなければならない。 文字列のテキスト内容はファイル名として解釈される 。ファイルが読み込まれ、ファイルの正確な内容が 文字列リテラルとなる。

実装によっては、ディレクトリ・トラバーサルによるセキュリティ脆弱性を回避するために、ファイル名を制限する場合がある。 考えられる制限としては、ファイル名内のパス構成要素を一切許可しないことが挙げられる。

デフォルトでは、インポート式は、-J スイッチで1つ以上のパスが渡されない限り、コンパイルされないことに注意。これは、 インポートするファイルの場所をコンパイラに指示する。これはセキュリティ機能である。

void foo()
{
    // ファイルfoo.txtの内容を表示する
    writeln(import("foo.txt"));
}

新しい式

NewExpression:
    new Type
    new Type [ AssignExpression ]
    new Type ( NamedArgumentListopt )
    NewAnonClassExpression

NewExpressionsは ガベージ コレクションされたヒープ上にデフォルトでメモリを割り当てる。

new 型フォームは型のインスタンスを構築し、それをデフォルトで初期化する。

Type(NamedArgumentList)フォームでは、同じ型の単一の初期化子、または より複雑な型の複数の引数を渡すことができる。 クラス型の場合、NamedArgumentListはクラスコンストラクタに渡される。 動的配列の場合、引数は初期配列長を設定する。 多次元動的配列の場合、各引数は 初期長に対応する(下記参照)。

int* i = new int;
assert(*i == 0);
i = new int(5);
assert(*i == 5);

Object o = new Object;
Exception e = new Exception("info");

auto a = new int[](2);
assert(a.length == 2);

Type[AssignExpression]形式はAssignExpressionと同じ長さの動的配列を割り当てる。 代わりに動的配列を割り当てる場合は、より一般的なType(NamedArgumentList)形式を使用することが推奨される。

注釈: 静的配列を直接割り当てることはできない。new (型エイリアスを使用する場合のみ)。

結果は、 他の修飾子に暗黙的に変換できるユニークな式となる。

immutable o = new Object;

クラスのインスタンス化

NewExpression がクラス型と共に、 ストレージクラスを持つ関数ローカル変数の初期化子として使用される場合、 scopeストレージクラスを持つ場合、 そのインスタンスはスタック上に割り当てられる

new ネストされたクラスの割り当てにも使用できる。

多次元配列

多次元配列を割り当てる場合、宣言は プレフィックス配列の宣言順と同じ順序で読み込まれる。

char[][] foo;   // 文字列の動的配列
...
foo = new char[][30]; // 30個の文字列の配列を確保する

上記の割り当ては、次のように書くこともできる。

foo = new char[][](30); // 30個の文字列の配列を確保する

ネストした配列を割り当てるには、複数の引数を使用できる。

int[][][] bar;
bar = new int[][][](5, 20, 30);

assert(bar.length == 5);
assert(bar[0].length == 20);
assert(bar[0][0].length == 30);
上記の代入は、次のものと同義である。
bar = new int[][][5];
foreach (ref a; bar)
{
    a = new int[][20];
    foreach (ref b; a)
    {
        b = new int[30];
    }
}

Typeid 式

TypeidExpression:
    typeid ( Type )
    typeid ( Expression )

"型"の場合、"型"に対応するクラスのインスタンスを返す TypeInfo "型"に対応する

IfExpression、式の型に対応するクラスのインスタンスを返す TypeInfo 式の型に対応する クラスを返す。 型がクラスである場合、動的型(すなわち、最も派生した型)のTypeInfoを返す。 式は常に実行される。

class A { }
class B : A { }

void main()
{
    import std.stdio;

    writeln(typeid(int));        // int
    uint i;
    writeln(typeid(i++));        // uint
    writeln(i);                  // 1
    A a = new B();
    writeln(typeid(a));          // B
    writeln(typeid(typeof(a)));  // A
}

式は

IsExpression:
    is ( Type )
    is ( Type : TypeSpecialization )
    is ( Type == TypeSpecialization )
    is ( Type : TypeSpecialization , TemplateParameterList )
    is ( Type == TypeSpecialization , TemplateParameterList )
    is ( Type Identifier )
    is ( Type Identifier : TypeSpecialization )
    is ( Type Identifier == TypeSpecialization )
    is ( Type Identifier : TypeSpecialization , TemplateParameterList )
    is ( Type Identifier == TypeSpecialization , TemplateParameterList )
TypeSpecialization: Type TypeCtor struct union class interface enum __vector function delegate super return __parameters module package

IsExpressionはコンパイル時に評価され、 式が有効な型であるかを確認するために使用される。さらに、 以下の形式も使用できる。

IsExpressionの結果は、条件が満たされるとtrue、満たされないとfalse となるブーリアンである。

Typeはテストされる型である。 構文的に正しい必要があるが 、意味的に正しい必要はない。 意味的に正しくない場合は、条件は満たされない。

型特殊化とは、型がパターンマッチされるである。

IsExpressionsは、 typeof式の型が正しくチェックされているかどうかを確認するために使用できる。 例えば、is(typeof(foo)) は、foo が有効な型である場合にtrue を返す。

基本フォーム

is ( )

型が意味的に正しい場合は条件を満たす。 型は構文的に正しい必要がある。

pragma(msg, is(5)); // エラー
pragma(msg, is([][])); // エラー
int i;
static assert(is(int));
static assert(is(typeof(i))); // 同一

static assert(!is(Undefined));
static assert(!is(typeof(int))); // intは式ではない
static assert(!is(i)); // iは値である

alias Func = int(int); // 関数型である
static assert(is(Func));
static assert(!is(Func[])); // 関数の配列は許可されないため、失敗する
Type xml-ph-0000@deepl.internal TypeSpecialization
is ( : 型特殊化 )

型が意味的に正しく、かつ TypeSpecialization と 同じであるか、または暗黙的に変換できる場合は、条件が満たされる。 TypeSpecialization は型のみ許可される。

alias Bar = short;
static assert(is(Bar : int)); // shortは暗黙的にintに変換される
static assert(!is(Bar : string));
is ( == TypeSpecialization )

TypeSpecializationが型である場合、 Typeが意味的に正しく、かつ TypeSpecialization と同じ型である場合に条件が満たされる。

alias Bar = short;
static assert(is(Bar == short));
static assert(!is(Bar == int));
もしTypeSpecializationがTypeCtorである場合 、TypeがそのTypeCtorであれば条件を満たす。

TypeSpecializationTypeCtorの場合、 Type がその TypeCtor であれば条件を満たす。

static assert(is(const int == const));
static assert(is(const int[] == const));
static assert(!is(const(int)[] == const)); // headは変更可能である
static assert(!is(immutable int == const));
TypeSpecialization が以下のいずれかである場合 xml-ph-0000@deepl.internal xml-ph-0001@deepl.internal xml-ph-0002@

TypeSpecialization 以下のいずれかである場合 struct union class interface enum __vector function delegate module package の場合、Type がこれらのいずれかであれば条件を満たす。

static assert(is(Object == class));
static assert(is(ModuleInfo == struct));
static assert(!is(int == class));

modulepackage のフォームは、他のフォームとは異なり、"型"がシンボル(型ではない)である場合に満たされる。 代わりに、isModuleisPackageの __traits を使用すべきである。 パッケージモジュールは、パッケージとモジュールの両方であるとみなされる。

TypeSpecializationもこれらのキーワードの1つである。

keywordcondition
supertrue 型がクラスまたはインターフェイスである場合
return true 型が関数、デリゲート、関数ポインタの場合
__parameters true 型が関数、デリゲート、関数ポインタの場合
class C {}
static assert(is(C == super));

void foo(int i);
static assert(!is(foo == return));
static assert(is(typeof(foo) == return));
static assert(is(typeof(foo) == __parameters));

See also: トレイト。

TraitTrait

識別子形式

条件が満たされる場合、Identifierは結果の型のエイリアスとして宣言される。 IdentifierフォームはIsExpression がStaticIfConditionまたはStaticAssertの最初の引数現れる場合にのみ使用できる。 xml-ph-0000@deepl.internal

is ( 識別子 )

型が意味的に正しい場合、条件は満たされる。 その場合、識別子は 型の別名として宣言される。

struct S
{
    int i, j;
}
static assert(is(typeof(S.i) T) && T.sizeof == 4);
xml-ph-0000@deepl.internal
alias Bar = short;

void foo()
{
    static if (is(Bar T))
        alias S = T;
    else
        alias S = long;

    pragma(msg, S); // short

    // Tが定義されていれば、スコープに残る
    if (is(T))
        pragma(msg, T); // short

    //if (is(Bar U)) {} // エラー、ここでUを宣言できない
}
is ( Identifier : 型特殊化 )

TypeSpecializationが型である場合、 Typeが意味的に正しく、かつ TypeSpecialization と同じであるか、 または暗黙的に変換できる場合に条件が満たされる。 IdentifierTypeSpecialization のエイリアスとして宣言される。

alias Bar = int;

static if (is(Bar T : int))
    alias S = T;
else
    alias S = long;

static assert(is(S == int));

TypeSpecializationIdentifier を含む型パターンである場合、 Identifier の型推論が試みられる。 これは、Typeまたはそれが暗黙的に変換される型に基づいて行われる。 この条件は、型パターンが一致した場合のみ満たされる。

struct S
{
    long* i;
    alias i this; // Sはlong*に変換される
}

static if (is(S U : U*)) // SがパターンU*とマッチする
{
    U u;
}
static assert(is(U == long));

識別子の型が決定される方法は、 テンプレートパラメータの型が TemplateTypeParameterSpecializationによって決定される方法と類似している。

is ( 識別子型 == 型特殊化 )

TypeSpecializationが型である場合、 Typeが意味的に正しく、かつ TypeSpecialization と同じ型である場合に条件が満たされる。 Identifierは、TypeSpecialization のエイリアスとして宣言される。

xml-ph-0000@deepl.internal
const x = 5;

static if (is(typeof(x) T == const int))   // satisfied、Tが定義された
    alias S = T;

static assert(is(T)); // Tはスコープ内にある
pragma(msg, T); // const int

TypeSpecialization がIdentifierを含む型パターンである場合、 Identifierの型推論がTypeに基づいて試みられる。 型パターンが一致した場合のみ、この条件が満たされる。

alias Foo = long*;

static if (is(Foo U == U*)) // FooはパターンU*にマッチする
{
    U u;
}
static assert(is(U == long));
TypeSpecializationがxml-ph-0000@deepl.internal形式の有効なキーワードである場合 、 同様に条件が満たされる。 識別子は以下のように設定される。

TypeSpecializationis(Type == Keyword) 形式の有効なキーワードである場合 、 同様に条件が満たされる。 識別子は以下のように設定される。

keywordalias type for Identifier
struct
union
class
interface
superベースクラスとインターフェースのシーケンス
enum列挙型の基本型
__vectorベクトルの静的配列型
functionTypeSeqの関数パラメータ型。 C言語およびD言語のスタイルの可変長引数関数の場合は、 可変長引数でないパラメータのみが含まれる。 型安全な可変長引数関数の場合は、... は無視される。
delegateデリゲートの関数型
return関数、デリゲート、または関数ポインタの戻り値の型
__parameters関数、デリゲート、または関数ポインタのパラメータシーケンス。 これには、パラメータの型、名前、およびデフォルト値が含まれる。
const
immutable
inout
shared
moduleモジュール
packageパッケージ
enum E : byte { Emember }

static if (is(E V == enum))    // satisfied、Eは列挙型である
    V v;                       // vはバイトであると宣言される

static assert(is(V == byte));

パラメータリストフォーム

is ( Type : TypeSpecialization , TemplateParameterList )
is ( Type == TypeSpecialization , TemplateParameterList )
is ( Type Identifier : TypeSpecialization , TemplateParameterList )
is ( Type Identifier == TypeSpecialization , TemplateParameterList )

より複雑な型はパターンマッチングできる。 TemplateParameterListは、 パターンマッチングされた部分に基づいてシンボルを宣言する。 暗示的なテンプレートパラメータのマッチング方法と類似している。

Example: テンプレートのインスタンス化に一致する

struct Tuple(T...)
{
    // ...
}
alias Tup2 = Tuple!(int, string);

static if (is(Tup2 : Template!Args, alias Template, Args...))
{
    static assert(__traits(isSame, Template, Tuple));
    static assert(is(Template!(int, string) == Tup2)); // 同じ構造体である
}
static assert(is(Args[0] == int));
static assert(is(Args[1] == string));

TypeSpecialization がエイリアステンプレートインスタンスの場合、型を一致させることはできない。

struct S(T) {}
alias A(T) = S!T;

static assert(is(A!int : S!T, T));
//static assert(!is(A!int : A!T, T));

Example: 連想配列の一致

alias AA = long[string];

static if (is(AA T : T[U], U : string)) // T[U]はパターンである
{
    pragma(msg, T);  // long
    pragma(msg, U);  // string
}

// 一致しない、Bはintではない
static assert(!is(AA A : A[B], B : int));

Example: 静的配列に一致する

static if (is(int[10] W : W[len], int len)) // W[len]はパターンである
{
    static assert(len == 10);
}
static assert(is(W == int));

// マッチしない、lenは10でなければならない
static assert(!is(int[10] X : X[len], int len : 5));
ph-0000@deepl.internalxml-ph-0000@deepl.internal

特殊キーワード

SpecialKeyword:
    __FILE__
    __FILE_FULL_PATH__
    __MODULE__
    __LINE__
    __FUNCTION__
    __PRETTY_FUNCTION__
xml-ph-0000@deepl.internalは、インスタンス化された時点でのソースファイル名と行番号に展開される。 ソースファイルのパスは コンパイラに任される。

__FILE__ および は、インスタンス化された時点でのソースファイル名と行番号に展開される。 ソースファイルのパスは コンパイラに任される。__LINE__

__FILE_FULL_PATH__ 展開すると、インスタンス化された時点でのソースファイルの絶対パス名となる。

__MODULE__ インスタンス化された時点でのモジュール名に展開される。

は、インスタンス化の時点における関数の完全修飾名に展開される。

__FUNCTION__ インスタンス化の時点で、関数の完全修飾名に展開される。

__PRETTY_FUNCTION__ __FUNCTION__ と同様ですが、 関数の戻り値の型、パラメータの型、 および属性も展開します。

例:

module test;
import std.stdio;

void test(string file = __FILE__, size_t line = __LINE__,
        string mod = __MODULE__, string func = __FUNCTION__,
        string pretty = __PRETTY_FUNCTION__,
        string fileFullPath = __FILE_FULL_PATH__)
{
    writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', " ~
        "pretty function: '%s',\nfile full path: '%s'",
        file, line, mod, func, pretty, fileFullPath);
}

int main(string[] args)
{
    test();
    return 0;
}

ファイルが /example/test.d にあったと仮定すると、次のような出力が得られる。

file: 'test.d', line: '13', module: 'test',
function: 'test.main', pretty function: 'int test.main(string[] args)',
file full path: '/example/test.d'

結合性と交換性

実装では、 算術結合性および交換性の規則に従って、 実行スレッド内で目に見える違いが 生じない限り、 "式"の評価を並べ替えることができる。

この規則により、浮動小数点式の結合または交換による並べ替えは一切排除される。

xml-ph-0000@deepl.internal