見出し画像

DartのNullSafetyについて確認してみる2

前回に続き、DartのNullSafety対応について、何が出来るようになったのかを確認してみる。

Working with nullable types

Null-aware operator

NullSafety対応前から使える Null-aware operator `?.` がよりスマートになったらしい。

NullSafety対応前に以下のようなコードを書くと、引数に null が入ってきた場合はエラーとなってしまう。message?.trim() の評価結果が null になる場合もあるので特におかしいわけではない。

String hoge(String message) {
 return message?.trim().toUpperCase();
}

で、エラーを回避するためにはこうする必要がある。

String hoge(String message) {
 return message?.trim()?.toUpperCase();
}

しかし、NullSafety対応後は以下のようなコードを書いてもエラーとはならなくなっている。

String? hoge(String? message) {
 return message?.trim().toUpperCase();
}

これは、message?.trim() の評価結果が変わったのではなく、Null-aware operatorを使ったメソッドチェーンでは、nullと評価された後の処理をスキップする、という仕組みになっているらしい。

Null-assertion operator

他の言語でもよくある `!` を Null-assertion operator と呼ぶらしい。強制的に non-nullable として扱うためのもの。

Late variables

`late` を付けて変数を宣言すると、コンパイル時ではなく実行時に制約を強制する事が出来る。

final で宣言したいけど、値が入るタイミングはインスタンスが生成された後、みたいな時に使えるはず。lateを付けた変数に初期化せずにアクセスしたり、この場合だとfinalなのに複数回初期化しようとするとエラーとなる。

class User {
 late final String firstName;
 late final String lastName;
 
 void setFullName(String first, String last) {
   firstName = first;
   lastName = last;
 }
 
 String getFullName() {
   return firstName + ' ' + lastName;
 }
}

Required named parameters

metaパッケージに入っていた @required に相当するものが、使えるようになった。コンパイル時にミスを検知できるようになるので、一括して置換しておくと良いかもしれない。

void hello({ required String message }) {
 print(message);
}

Abstract fields

NullSafety対応後に以下のようなコードを書くとエラーとなるらしい。

abstract class Hoge {
 String name;
}

で、getter と setter をそれぞれ定義すればOKらしいが面倒くさいので、abstract を付けて変数を宣言できるようになったらしい。

abstract class Hoge {
 abstract String name;
}

Nullability and generics

ジェネリクスにおいても ? を付けることで nullable であることを表現できる。

以下のようなコードを書いた時に、object に null が入っている時は object as T としても null になるらしい。

class Box<T> {
 T? object;
 Box.empty();
 Box.full(this.object);

 T unbox() => object as T;
}

Core library changes

The Map index operator is nullable

Mapの値を参照する時は、キーが存在するか分からないので必ず nullable になる。なので、NullSafety対応後はそれを考慮して、Null-assertion operator を付けるなりする必要がある。

var map = {'key': 'value'};
print(map['key']!.length);

No unnamed List constructor

List のデフォルトコンストラクタ List() がなくなったらしい。もし使ってたら [] とかに置き換えればとりあえずOKそう。

Cannot access Iterator.current before or after iteration

iterator.current が null を返すようになったので E ではなく E? になると。これも使っていたら適宜対応すればOKそう。

最後に

やはり、地味ではあるが理解しておくとより安全なコードを、より理解しやすい形で書けるようになる気がする。


この記事が気に入ったらサポートをしてみませんか?