0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Dartのnullについてのまとめ

Posted at

Dartのnullの扱い方を何度も調べている気がするので、まとめてみたいと思います。
公式ドキュメントから抜き出し・意訳・追記しています。(訳に誤りがありましたら申し訳ありません。)

Dartのnullのコンセプト

・堅固なnull Safetyにするために、Dartの変数は、デフォルトで ‘non-nullable’ になっています。この時、変数には、宣言された型の値のみをセットでき、nullはセットできません。 (e.g. int i=42)
・変数をnullableであると明示した時だけ、nullと宣言された型の値の両方をセットできるようになります。(e.g. int? i)
・堅固なnull Safetyによって、ランタイムエラーを引き起こす可能性のある箇所を、コーディング時に気がつくことができるエラーに変えます。このおかげで、アプリをデプロイする前に、これらのエラーを修正しておくことができます。

(「堅固なnull Safety」は、原文では、"Sound null Safety" となっています。"Sound" は形容詞で、「健全な、堅固な」という意味があるんですね。知りませんでした。)

復習

なんと公式ドキュメントに、解説と練習問題のページがあります。なんて親切なのでしょう。

? → null許容型であることを明示する

型の後ろに「?」をつけると、null許容型(nullable)になります。逆にいうと、「?」がついていない時は、nullは入れられません。

Listの時は、以下のような扱いになるようです。

  //List自体がnullable
  List<String>? aNullableListOfStrings;
  //Listの要素がnullable
  List<String?> aListOfNullableStrings = ['one', null, 'three'];

! → null許容型を‘non-nullable’と同じ扱いにする

nullableな型で、nullでないのが確かな場合、変数や関数の後ろに!をつけることで、‘non-nullable’と同じように扱うことができます。

※nullになる可能性のあるところで「!」をつけてしまうと、ランタイムエラーを生んでしまうので、nullでないことを "you are very sure" な時だけ使ってください。とのこと。

例(変数の場合):

 List<int?> listThatCouldHoldNulls = [2, null, 4];
//一つ目の要素はnullでないので、「!」をつけてintに代入する(つけないとコンパイルエラーになる)
  int b = listThatCouldHoldNulls.first!; // first item in the list

例(関数の場合):

int? couldReturnNullButDoesnt() => -3;
//nullは返さないので、「!」をつけて、その後に関数を使える
int c = couldReturnNullButDoesnt()!.abs(); // absolute value

?. → nullではない時だけ実行する

nullが入っているかもしれない値を扱う時に、「?.」を使うと、その後の式は、nullでない場合だけに実行されます。

例:

//"nullableString" がnullでない時は、lengthの値を返す。nullの場合はnullを返す
nullableString?.length;

?? → nullだったら違う値をセットする

例:

///notnullValueがnullでない場合に、notnullValueを、nullの場合nullValueをセットする
    String value = notnullValue ?? nullValue;

type promotion → nullでないことの自動判定

以下のような場合、Dartはnullableの変数の値がnullでないことを検知して、‘non-nullable’の型と同じように扱えるようになります。これを、"type promotion" といいます。

・利用箇所より上で、値が必ずセットされている場合
・nullチェックがされていて、nullの場合にreturnやthrow Exceptionになっている場合

例:

int getLength(String? str) {
  // nullの場合は0を返す
  if(str==null){
      return 0;
   }
  //本来 "str" はnullableなので、.lengthをつけたらコンパイルエラーになるが、
  //上でnullチェックしてreturnしていることにより、エラーにならない。
  return str.length;
}

late → 後で値を設定する

変数宣言の前に「late」をつけることで、Dartに以下のことを伝えます。
・まだ値をセットしていない。
・後で値をセットする予定
・変数が使われる前に、値をセットすることを確信している

late で宣言した変数を使う前に値をセットしていないと、エラーが発生します。
※メモ:ただ、試したみたところ、このエラーは、コンパイルエラーではなく実行時エラーのようでした。

例:

class Meal {
//lateで宣言
  late String _description;

  set description(String desc) {
    _description = 'Meal description: $desc';
  }

  String get description => _description;
}

void main() {
  final myMeal = Meal();
  myMeal.description = 'Feijoada!';//この行をコメントアウトすると、実行時エラー
  print(myMeal.description);
}

特別な使い方として、初期値が設定されている変数に「late」をつけると、その変数が使われる時に、初めて初期値が設定されます。初期値設定のコストが高く、必ずしも必要にならない時に便利です。

例:

class CachedValueProvider {
  late final _cache = _computeValue();//初期値設定しているが、lateをつけている。
  int get value => _cache;
}

void main() {
  print('Calling constructor...');
  var provider = CachedValueProvider();
  print('Getting value...');
  print('The value is ${provider.value}!'); //ここで初めて初期値の設定がよばれる
}

感想

曖昧な理解のままに、場当たり的に?をつけたりしてしまっていましたが、ようやくすっきり理解できた気がします。Dartさんのnull Safetyに対するこだわりも伝わってきました。Dartの公式ドキュメントはとても親切であることがわかったので、もっと活用していきたいです。

情報源

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?