🍣

【Dart入門(2)】演算子まとめ|...?,??, ?., 三項間演算子, is, as,...など解説

に公開

Dartの演算子解説

Dartで用いられる演算子について解説していきます。

1. 演算子の優先順位と結合則

Dartでは演算子に優先順位(Precedence)と結合則(Associativity)があり、これは演算の順序に影響します。例として:

  • */%(乗算・除算系)は +-(加減算)より優先される。
  • ロジカル演算子 &&||== より優先度が低い。

例えば:

if (n % i == 0 && d % i == 0) { ... }

これは括弧で明示しなくても期待通りの順序で評価されます。


2. 算術演算子

演算子 意味
+, - 加算/減算
-expr 単項マイナス(符号反転)
* 乗算
/ 割り算(結果は double
~/ 整数除算(結果は int
% 剰余(あまり)

サンプル:

// +と-
int plus = 1 + 2;
int minus = 1 - 2;
// 符号反転
int reverse_plus = -plus;

assert(5 / 2 == 2.5);
assert(5 ~/ 2 == 2);
assert(5 % 2 == 1);

インクリメント/デクリメント演算もサポート:

  • ++var (前置)/var++ (後置)
  • --varvar--
    それぞれ動作と戻り値に違いがあります。
int num = 0;
int num1 = ++num;
assert(num1 == 1);
assert(num == 1);

num = 0;
int num2 = num++;
assert(num2 == 0);
assert(num == 1);

3. 等価・比較演算子

  • ==, !=:等しい/等しくない
  • >, <, >=, <=:大小比較

等価比較においては:

  • 両方が nulltrue
  • 片方だけが nullfalse
  • その他 → 左側のオブジェクトの == メソッドを呼び出します。

完全に同一オブジェクトかを確認したい場合は、identical() を使用します。

assert((1 >= 0), true);
assert((-1 < 0), false);

4. 型チェック・キャスト演算子

  • is:指定の型かどうかを確認
  • is!:指定の型でないか確認
  • as:指定の型へのキャスト(失敗すると例外)

例:

if (obj is Person) {
  // 安全に Person として扱える
}
(employee as Person).firstName = 'Bob';

5. 代入演算子

  • 標準代入:=
  • Null代入:??=(左辺が null のときのみ代入)
int? num = null;
num ??= 1;
print(num);
  • 複合代入:+=, -=, *=, /=, など(例:a += ba = a + b の意味

6. 論理演算子

  • !expr:論理否定
  • &&:AND
  • ||:OR

例:

// doneでなくかつ(col == 0かcol == 3)の場合
if (!done && (col == 0 || col == 3)) { ... }

7. ビット演算子・シフト演算子

  • &, |, ^:AND・OR・XOR
  • ~expr:ビット反転(NOT)
  • <<, >>:左・右シフト
  • >>>:符号なし右シフト(Dart 2.14以上)([dart.dev][1])

例えば:

assert((value & bitmask) == 0x02);
assert((value << 4) == 0x220);

8. 条件演算子

これはよく出てくる演算子なので覚えておいた方が良いです。

  • 三項演算子:condition ? expr1 : expr2
  • Null合体演算子:expr1 ?? expr2expr1が null でなければそれを返す)

例:

// isPublicがtrueなら'public'でそうでないなら'private'
var visibility = isPublic ? 'public' : 'private';
// nameがnullなら'Guest'、そうでないならname
String playerName(String? name) => name ?? 'Guest';

9. カスケード記法(Cascade Notation)

複数のメソッド呼び出しやプロパティ設定を連鎖させて記述できます
これは、PaintというクラスのプロパティにcolorやstrokeWidthがあるとき、インスタンス化→プロパティを変更の時などに使用します。..という記号が出てきたら、カスケード記法と認識できれば良いです。

var paint = Paint()
  ..color = Colors.black
  ..strokeWidth = 5.0;

null許容の場合は ?.. を使うことで安全に操作可能です。

class Person {
  String? name;
  int? age;

  void greet() => print('Hello, I am $name, $age years old.');
}

void main() {
  Person? p = null;

  // ✅ p が null なのでカスケードはスキップされ、エラーにならない
  p?..name = 'Alice'
   ..age = 20
   ..greet();

  // p をインスタンス化すると処理される
  p = Person();
  p?..name = 'Bob'
   ..age = 25
   ..greet(); // Hello, I am Bob, 25 years old.
}

10. スプレッド演算子

リストやセットの展開を簡潔に記述できます(Dart構文の一部):

var a = [1,2];
var b = [2,3];
List<int>? c = null;

var list = [...a, ...b]; //これはaとbという配列の展開です。
print(list);
// [1,2,2,3]
var maybeList = [...?c];
print(maybeList);
// []

優先順位は低く、どんな式でも展開対象にできます。


11. その他の演算子

  • 関数呼び出し:()(例:f()
  • 添え字アクセス:[](例:list[0]
  • 条件付き添え字アクセス:?[](例:list?[0]
void main() {
  List<String>? maybeList;

  // maybeList は null
  print(maybeList?[0]); // null(エラーにはならない)

  // 値を代入
  maybeList = ['x', 'y'];
  print(maybeList?[1]); // y
}
  • メンバアクセス:.?.
class Person {
  String? name;
  void greet() => print('Hello, I am $name');
}

void main() {
  Person? p;

  // 通常のアクセス
  p = Person()..name = 'Alice';
  p.greet(); // Hello, I am Alice

  // null 安全アクセス
  p = null;
  p?.greet(); // 何も起きない(エラーにはならない)
}
  • 非nullアサーション:!(例:foo!.bar
void main() {
  String? maybeName = 'Bob';

  // 「絶対に null じゃない!」とコンパイラに保証する
  String name = maybeName!;
  print(name); // Bob

  // null の場合は実行時エラー
  maybeName = null;
  print(maybeName!); // ❌ 実行時にエラー(Null check operator used on a null value)
}

まとめ

Dart の演算子は多彩で、演算順序、型チェック、代入、条件式、カスケード構文、スプレッドなど、コードの簡潔性と表現力を高めるのに役立ちます。

Discussion