Null Safetyとは?

はじめに

Flutter を勉強していると、Null Safetyとはなんぞや?という疑問が湧いてきたので

私なりの解釈で書き留めます。

Null Safetyとは?(ヌルセーフティ)

ざっくり言うと

「プログラム中のNullが安全に扱われているよー」

という状態を表す用語です。

Nullって?

Null=「値が存在しない」ということ。

※プログラミングにおいては「null ≠ 0」 「0」は「値が0である」

例えばnameという変数があり、その中身を定義していなければ
name=nullとなります。

// nameがnullの状態
String name;

Flutter2(Dart2.12以降)からNull Safetyに対応

FlutterではFlutter2(Dart2.12以降)からNull Safetyに対応しています。

つまりNon-Nullable By Default(NNBD)の考え方が導入されました。

「デフォルトの変数宣言ではその変数にnullを入れちゃダメですよー」という考え方です。

例えば先ほどのname変数はnullなのでNNBDでは必ず中身を定義する必要があります。

// nameがnullではない状態
String name = 'ななこし';

それではなぜプログラムにnullが入っていると良くないのでしょうか?

nullを扱うことの問題点

プログラムの中でNullを使うと

色々なところで値があったりなかったりするとバグの温床になり得る

NullPointerException(ぬるぽ)・Null参照エラー

nullが設定されている変数を参照しようとすると発生するエラー

比較演算子が使えない

例えば、Null値と数値を比較する場合、その結果はNull値になります。

【例】Null Safetyが適応されているdartで以下のようなコードを書いてみる

・もしNullが0と等しいなら、trueと出力する。それ以外はfalseと出力する。

if (null == 0) {
    print('true');
  } else {
    print('false'); 
}
The operand can't be null, so the condition is always 'false'.

オペランドを null にすることはできないため、条件は常に「false」になります。

このように表示されます。

Null Safetyのメリット

・Null によって発生し得るエラーを教えてくれる

先ほどのコード例のように

The operand can't be null, so the condition is always 'false'.

オペランドを null にすることはできないため、条件は常に「false」になります。

といったように「ここでNullを使うことによって想定外の結果になりますよ」と警告してくれます。

・生産性や保守性の向上

nullがないことを前提に最適化を行うことができる。

nullチェックやその他の準備が必要な時も最適な処理ができる。ムダが少なくなる。

Nullable型とNon-Nullable型

変数を宣言する時に型に?を付けると付けない場合nullを許容されるかどうかを変える事ができます。

・?を付けてnullが入る可能性がある型をNullable型(null許容型)

// ?を付けてnullを許容する
String? name;
print(name); // null

・?を付けずにnullが入らない型をNon-Nullable型(null非許容型)といいます。

// ?がないのでnullが非許容 = nullが入らない型
String name;
// Non-nullable instance field 'name' must be initialized.
// NULL 非許容のインスタンス フィールド 'name' を初期化する必要があります。

また、Non-Nullable型にnullを入れようとするとコンパイルエラーが出ます

String name = null;
// A value of type 'Null' can't be assigned to a variable of type 'String'.
// 「Null」型の値を「String」型の変数に割り当てることはできません。

nullを扱うことが必ずしも問題とは限らない

先ほどはnullの問題点を述べましたがnullを扱うことが必ずしも問題とは限りません。

大事なのはNullを適切に取り扱うことです。

下記のようにFlutter(Dart)にはnullを考慮した演算子があります。

これらの演算子はNull-aware演算子と呼ばれます。

?.演算子

変数のnullをチェックしてからアクセスします。

//?.演算子を使って変数のnullをチェック

void main(){
  String? name2;
  int? answer2;
  
  name2 = null;
  answer2 = name2?.length;
  print(answer2);
}

// console: null
//?.演算子がない場合nullの可能性をチェックをしていない為コンパイルエラーが出る

void main(){
  String? name2;
  int? answer2;
  
  name2 = null;
  answer2 = name2.length;
  print(answer2);
}

// The property 'length' can't be unconditionally accessed because the receiver can be 'null'.
// レシーバーが「null」になる可能性があるため、プロパティ「length」に無条件でアクセスすることはできません。

??演算子

代入する変数がnullでないならその値を使い、nullなら右の値を使います。

void main() {
  int? count;
  int? answer;

  // countがnullだったらanswerが右の値になる
  count = null;
  answer = count ?? 50;
  print(answer); //50

  // ??を使わないパターン!=
  // countがnullだったらanswerはnull
  // それ以外だったらanswerは0
  if (count != null) {
    answer = count;
  } else {
    answer = 0;
  }
  print(answer); //0
}

??=演算子

変数がnullでないなら値を変えず、nullなら右の値を使います。

void main() {
  int? count;

  count = 100;
  count ??= 0;
  print(count); //100
 
  count = null;
  count ??= 0;
  print(count); //0

  // ??=を使わないパターン
  count = count ?? 50;
  print(count); //0
}

コメント

タイトルとURLをコピーしました