🔷

Dartの?? ??= ?. …?演算子(Null-aware演算子 / null-aware operators)について

2024/02/25に公開1

はじめに

  • はてな2つの演算子『??』とか、はてな+ドットの演算子『?.』とかややこしいのでまとめてみました。
  • Dartでは『nullの可能性があるものを扱う時に便利な演算子』がある。それがこの子達。

??

  • ??演算子(null演算子)と呼ばれる。
  • Dartにおいて、??は「if null」を意味する。
  • ??演算子の左側の式がnullでなければ、その値を返す。左側の式がnullなら、右側の式の値を返す。
void main() {
  print(1 ?? 3);  // <-- 1
  print(null ?? 12);  // <-- 12
  print(0 ?? 1);  // <-- 0
  print(null ?? null ?? 30); // <-- 30
}

??=

  • ??=演算子。英語ではnull-aware assignment operator
  • 変数の現在の値がnullの時は代入を行う。変数の現在の値がnullでない時は代入が行われない。
void main() {
  int? num; // <-- 初期化してないのでnumはnull
  print(num); // <-- null

  num ??= 5;
  print(num); // <-- 5

  num ??= 100; // <-- numの値はnullではないので、100の代入は行われない。
  print(num); // <-- 5
}

?.

  • ?.演算子。英語ではnull-aware access(method invocation) operator
  • ?.演算子は、nullかもしれないオブジェクトの『プロパティ』や『メソッド』にアクセスしようとしてアプリがクラッシュするのを防ぐ。
  • オブジェクトがnullの場合、nullが返ってくる。下の例で言うと、valuenullなので?.演算子を使用して書くとnullが返ってくる。
  • チェーンしてワンライナーで書くこともできる。
void main() {
  String? value; // <-- 初期化してないのでvalueはnull
  print(value.toLowerCase()); // <-- ?.演算子を使用せず、かつvalueがnullのためエラー
  print(value?.toLowerCase()); // <-- オブジェクト(value)がnullなのでnull
  print(value?.toLowerCase().toUpperCase());  // <-- toLowerCase()の後ろで?.演算子を使用せず、かつvalueがnullのためエラー
  print(value?.toLowerCase()?.toUpperCase()); // <-- オブジェクト(value)がnullなのでnull(チェーンしてワンライナーで記述)

  print((value != null) ? value.toLowerCase() : null); // 2つ目のprint文はこのコードと等価。
}
class HogeObject{
  int? num;
  
  HogeObject({this.num});
}

void main(){
  var hogeObject = null;
  print("${hogeObject?.num?.toString()}"); // <-- null
  print("${hogeObject?.num}"); // <-- null
  
  HogeObject hogeObject_1 = HogeObject();
  print("${hogeObject_1?.num?.toString()}"); // <-- null
  print("${hogeObject_1?.num}"); // <-- null

  HogeObject hogeObject_2 = HogeObject(num: 50);
  print("${hogeObject_2?.num?.toString()}"); // <-- 50
  print("${hogeObject_2?.num}"); // <-- 50
}
  • ?.演算子を使わずに書くと以下のようにnullでないことをいちいちif文でチェックすることになる。これを避けるため上記のように?.演算子を使用する。
void main() {
  String? input;
  if (input != null) {
    print(input.length);
    print(input.toLowerCase());
  }
}

…?

  • 英語ではnull-aware spread operator
  • 日本語を使用して表現すると『null-awareスプレッド演算子』か。
  • スプレッド演算子を使用する際、null要素を追加することを防ぐ。
void main() {
  Map? map_1 = {1: 'マンゴー', 2: 'リンゴ'};
  Map? map_2 = {3: 'みかん', 4: 'メロン'};
  Map? map_3 = null;
  var mergeMap = {...?map_1, ...?map_2, ...?map_3}; // null-awareスプレッド演算子を使用してマージする
  print(mergeMap); // <-- {1: マンゴー, 2: リンゴ, 3: みかん, 4: メロン}

  List<int> numList = [1, 2, 3];
  List<String>? stringList; // <-- 初期化してないのでstringListはnull
  print(['おはよう', ...stringList]);  // <-- エラー
  print(['おはよう', ...?stringList]); // <-- [おはよう]
  print([0, ...?stringList, ...numList]); // <-- [0, 1, 2, 3]
}

(最後にソッといいねボタンやバッジを贈るボタンを押して頂けたら幸いですm(_ _)m)

参照

https://jelenaaa.medium.com/what-are-in-dart-df1f11706dd6
https://dart.dev/codelabs/dart-cheatsheet
https://okutaro.com/2020/09/19/2020-9-19-dartnull-aware演算子について/
https://www.darttutorial.org/dart-tutorial/dart-null-aware-operators/
https://www.educative.io/answers/what-are-spread-operators-vs-null-aware-spread-operators-in-dart

Discussion

Cat-sushiCat-sushi
  • スプレッド演算子を使用する際、null要素を追加することを防ぐ

?の右にあるコレクションのnull要素は展開されます。
?の右にあるnull可コレクション変数がnullの場合にその展開をスキップします。