演算子
Dart は、次の表に示す演算子をサポートしています。この表は、Dart の演算子の関連性と演算子の優先順位を高いものから低いものへと示したもので、Dart の演算子関係の近似値です。これらの演算子の多くは、クラス・メンバとして実装できます。
説明 | 演算子 | 関連性 |
---|---|---|
単項ポストフィックス | expr++ expr-- () [] ?[] . ?. ! | None |
単項接頭辞 | -expr !expr ~expr ++expr --expr await expr | None |
乗除 | * / % ~/ | Left |
増減 | + - | Left |
シフト | << >> >>> | Left |
ビット毎AND | & | Left |
ビット毎XOR | ^ | Left |
ビット毎OR | | | Left |
関係テストと型テスト | >= > <= < as is is! | None |
等価 | == != | None |
論理積 | && | Left |
論理和 | || | Left |
nullの場合 | ?? | Left |
条件付き | expr1 ? expr2 : expr3 | Right |
カスケード | .. ?.. | Left |
割り当て | = *= /= += -= &= ^= etc. | Right |
WARNING
先ほどの表は、あくまでも参考程度に使っていただきたい。演算子の優先順位と関連性の概念は、言語文法にある真理の近似値です。Dart言語仕様で定義されている文法に、Dartの演算子関係の正式な動作が記載されています。
演算子を使用すると、式が作成されます。演算子式の例をいくつか挙げよう:
a++
a + b
a = b
a == b
c ? a : b
a is T
演算子の優先順位の例
演算子表では、各演算子はそれに続く行の演算子よりも優先順位が高くなります。例えば、乗法演算子 %
は等号演算子 ==
よりも優先順位が高く、等号演算子は論理 AND 演算子 &&
よりも優先順位が高い。この優先順位は、次の2行のコードが同じように実行されることを意味します:
// 括弧は読みやすさを向上させる。
if ((n % i == 0) && (d % i == 0)) ...
// 読みにくいが、同等だ。
if (n % i == 0 && d % i == 0) ...
WARNING
オペランドを2つ取る演算子の場合、左端のオペランドがどのメソッドを使うかを決定します。例えば、 Vector
オブジェクトと Point
オブジェクトがある場合、 aVector + aPoint
は Vector
の加算 (+
) を使用します。
算術演算子
Dartは次の表に示すように、通常の算術演算子をサポートしている。
Operator | Meaning |
---|---|
+ | 追加 |
- | 引く |
-expr | 単項マイナス、否定としても知られる(式の符号を逆にする) |
* | 乗算 |
/ | 分割する |
~/ | 整数の結果を返す除算 |
% | 整数除算の余りを得る(モジュロ) |
例:
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 結果はダブル
assert(5 ~/ 2 == 2); // 結果は int
assert(5 % 2 == 1); // 残り
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Dartはまた、前置演算子と後置演算子の両方のインクリメントとデクリメントをサポートしている。
演算子 | 意味 |
---|---|
++var | var = var + 1 (expression value is var + 1 ) |
var++ | var = var + 1 (expression value is var ) |
--var | var = var - 1 (expression value is var - 1 ) |
var-- | var = var - 1 (expression value is var ) |
例:
int a;
int b;
a = 0;
b = ++a; // bが値を取得する前にaをインクリメントする。
assert(a == b); // 1 == 1
a = 0;
b = a++; // bがその値を取得した後、aをインクリメントする。
assert(a != b); // 1 != 0
a = 0;
b = --a; // bが値を取得する前にaをデクリメントする。
assert(a == b); // -1 == -1
a = 0;
b = a--; // bがその値を取得した後、aをデクリメントする。
assert(a != b); // -1 != 0
等式演算子と関係演算子
以下の表に、等号演算子と関係演算子の意味を示す。
演算子 | 意味 |
---|---|
== | イコール。 |
!= | 同等ではない |
> | より大きい |
< | 未満 |
>= | 以上 |
<= | 以下 |
2つのオブジェクト x と y が同じものを表しているかどうかを調べるには、 ==
演算子を使います。(まれに2つのオブジェクトが全く同じオブジェクトかどうかを知る必要がある場合は、代わりに identical() 関数を使います)。以下に ==
演算子の動作を示します:
xまたはyがNULLの場合、両方がNULLならtrueを返し、片方だけがNULLならfalseを返す。
引数 y で
==
メソッドを x に対して呼び出した結果を返す。(その通り、==
のような演算子は最初のオペランドに対して呼び出されるメソッドです。詳しくは演算子を参照してください)。
以下は、各等式演算子と関係演算子の使用例である:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
型テスト演算子
as
, is
, is!
演算子は、実行時に型をチェックするのに便利である。
演算子 | 意味 |
---|---|
as | タイプキャスト(ライブラリの接頭辞を指定するためにも使われる) |
is | オブジェクトが指定された型を持っていれば真 |
is! | オブジェクトが指定された型を持っていない場合は真 |
もし obj
が T
で指定されたインターフェイスを実装していれば、obj is T
の結果は真である。例えば、obj is Object?
は常に真である。
オブジェクトがその型であることが確実な場合に限り、オブジェクトを特定の型にキャストするには as
演算子を使用する。例
(employee as Person).firstName = 'Bob';
オブジェクトが T
型であるかどうか確信が持てない場合は、オブジェクトを使う前に is T
を使って型を確認する。
if (employee is Person) {
// タイプチェック
employee.firstName = 'Bob';
}
note
コードは等価ではない。もし employee
が NULL または Person
でない場合、最初の例は例外をスローする。
代入演算子
すでに見たように、=
演算子を使って値を代入することができます。代入先の変数がNULLの場合のみ代入するには、 ??=
演算子を使います。
// aに値を割り当てる。
a = value;
// bがNULLの場合、bに値を割り当てる。
b ??= value;
複合代入演算子 +=
などは、演算と代入を組み合わせたものである。
= | *= | %= | >>>= | ^= |
+= | /= | <<= | &= | |= |
-= | ~/= | >>= |
複合代入演算子がどのように働くかを説明しよう:
Compound assignment | Equivalent expression | |
---|---|---|
For an operator op: | a op= b | a = a op b |
Example: | a += b | a = a + b |
次の例では、代入演算子と複合代入演算子を使用しています:
var a = 2; // =を使用して割り当てる。
a *= 3; // 割り当てと掛け算: a = a * 3
assert(a == 6);
論理演算子
論理演算子を使用すると、ブール式を反転させたり結合させたりすることができます。
演算子 | 意味 |
---|---|
!expr | 式を反転させます(偽を真に、逆を偽にします)。 |
|| | 論理和 |
&& | アンド |
以下は論理演算子の使用例である。
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
ビット演算子とシフト演算子
Dartでは、数値の個々のビットを操作することができる。通常、ビット演算子やシフト演算子は整数に対して使用します。
演算子 | 意味 |
---|---|
& | アンド |
| | OR |
^ | 排他的論理和 |
~expr | 単項ビットごとの補数(0が1になり、1が0になる) |
<< | 左シフト |
>> | 右シフト |
>>> | 符号なし右シフト |
note
大きなオペランドや負のオペランドを持つビット演算の動作は、プラットフォームによって異なる場合があります。詳しくは、ビット演算のプラットフォームの違い を参照してください。
以下はビット演算子とシフト演算子の使用例である:
final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); // AND
assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR
assert((value << 4) == 0x220); // 左シフト
assert((value >> 4) == 0x02); // 右シフト
// 右シフトの例では、オペランド値が32ビットにマスクされると変化するため、ウェブ上での動作が異なる:
assert((-value >> 4) == -0x03);
assert((value >>> 4) == 0x02); // 符号なし右シフト
assert((-value >>> 4) > 0); // 符号なし右シフト
version-note
演算子 >>>
(_triple-shift_または_unsigned shift_として知られている)は、少なくとも2.14の言語バージョンを必要とします。
条件式
Dartには2つの演算子があり、if-else文を必要とするような式を簡潔に評価することができます:
condition ? expr1 : expr2
: もし condition が真なら、expr1 を評価する。 (その値を返す); そうでなければ、expr2の値を評価して返す。expr1 ?? expr2
: expr1 がNULLでない場合、その値を返す。 そうでなければ、expr2の値を評価して返す。
ブーリアン式に基づいて値を割り当てる必要がある場合は、?
と:
の使用を検討する。
var visibility = isPublic ? 'public' : 'private';
ブーリアン式がnullをテストする場合は、??
の使用を検討する。
String playerName(String? name) => name ?? 'Guest';
先ほどの例は、少なくとも他の2通りの書き方ができただろうが、これほど簡潔には書けなかった:
// 少し長いバージョンでは、?:演算子を使用する。
String playerName(String? name) => name != null ? name : 'Guest';
// 非常に長いバージョンでは、if-else文を使用する。
String playerName(String? name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
カスケード表記法
カスケード (..
, ?..
) を使うと、同じオブジェクトに対して一連の操作を行うことができます。インスタンスメンバにアクセスするだけでなく、同じオブジェクトのインスタンスメソッドを呼び出すこともできます。これにより、一時変数を作成する手間が省け、より流動的なコードを書くことができます。
次のコードを考えてみよう:
var paint = Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
コンストラクタ Paint()
は Paint
オブジェクトを返します。カスケード記法に続くコードはこのオブジェクトを操作し、返されるかもしれない値を無視します。
前の例は、このコードと等価である:
var paint = Paint();
paint.color = Colors.black;
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 5.0;
カスケードが操作するオブジェクトがNULLである可能性がある場合、最初の操作には null-shorting カスケード(?..
)を使用する。?..
から始めることで、そのヌル・オブジェクトに対してどのカスケード操作も試みられないことが保証される。
querySelector('#confirm') // オブジェクトを取得する。
?..text = 'Confirm' // そのメンバーを使うように。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'))
..scrollIntoView();
version-note
?..
構文は少なくとも2.12以上の言語バージョンが必要です。
先ほどのコードは、以下のコードと等価である:
var button = querySelector('#confirm');
button?.text = 'Confirm';
button?.classes.add('important');
button?.onClick.listen((e) => window.alert('Confirmed!'));
button?.scrollIntoView();
カスケードをネストすることもできる。例えば
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
実際のオブジェクトを返す関数でカスケードを構築するように注意してください。例えば、以下のコードは失敗する:
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // エラー:メソッド 'write' は 'void' に対して定義されていません。
sb.write()
コールはvoidを返すので、void
でカスケードを構築することはできない。
note
厳密に言えば、カスケードの「ダブルドット」表記は演算子ではない。Dart構文の一部に過ぎない。
その他のオペレーター
他の例で、残りの演算子のほとんどを見たことがあるだろう:
演算子 | 名前 | 意味 |
---|---|---|
() | Function application | 関数呼び出しを表す |
[] | 添え字アクセス | オーバーライド可能な [] 演算子の呼び出しを表す。 例: インデックス 1 の要素にアクセスするために fooList[1] に int 1 を渡す。 |
?[] | 条件付き添え字アクセス | [] と同じだが、左端のオペランドはNULLでもよい。; 例: fooList?[1] は fooList に int 1 を渡し、fooList が NULL でない限りインデックス 1 の要素にアクセスする。(この場合、式はnullと評価される) |
. | メンバーアクセス | 式のプロパティを指す; 例: foo.bar は、式 foo からプロパティ bar を選択する。 |
?. | 条件付きメンバーアクセス | . と同じだが、左端のオペランドは NULL でもよい。; 例: foo?.bar は、foo が NULL でない限り、foo 式からプロパティ bar を選択する。 (この場合、foo?.bar の値はNULLである。) |
! | 非NULLアサーション演算子 | 式をその基礎となる非 null 型にキャストし、キャストに失敗した場合は実行時例外をスローします。; 例: foo!.bar は foo が NULL でないことを保証し、プロパティ bar を選択する。ただし foo が NULL の場合は例外が発生する。 |
演算子 .
, ?.
, ..
については、Classes を参照してください。