本記事ではDart(2.12)が持つNullSafetyについて紹介します。
公式の紹介ページを参考に、日本語訳+必要な箇所のみ抜粋した形での説明となります。
Null Safetyとは
NullSafetyとは、簡単に言うと「変数にnull入れるの禁止令」といった感じです。
プログラムを書いたことがある方であれば経験があると思いますが、変数にnullが入っていたせいでアプリがクラッシュしたり、他の問題が出たりすることが多々あると思います。基本的にはNull SafetyによってNullを許容しないようにしたほうが安全なコードが書けると考えられます。
Null許容
ただ、プログラムを書くにあたって、アルゴリズムや設計によってはnullを扱いたいケースが当然出てきます。そういった際に使うのが、Null許容型です。
上に記載いた通り、Nullが許容されていない変数にnullを代入(または初期化せずnullのままに)するとビルドエラーとなります。
void main() { String data; data = null; // ここでエラー print('data is $data.'); }
ここで、変数名の前の?を追記するとビルドエラーが消え、プログラムが実行できるようになります。これがNull許容です。以下の例では、”data is null”と表示されます。
void main() { String ?data; data = null; print('data is $data.'); }
リストでの例
次は、リストの中身またはリスト自体をNull許容にする例です。
void main() { List<String> aListOfStrings = ['one', 'two', 'three']; //null非許容のリスト List<String> ?aNullableListOfStrings; // リスト自体がnull許容 List<String?> aListOfNullableStrings = ['one', null, 'three']; // リストの中身のデータがnull許容 print('aListOfStrings is $aListOfStrings.'); print('aNullableListOfStrings is $aNullableListOfStrings.'); print('aListOfNullableStrings is $aListOfNullableStrings.'); }
Null アサーション演算子 (?)
Null許容型の変数を、Null非許容型の変数に代入するようなケースでは、ビルドエラーが発生します。
(Nullを許容しないにもかかわらず、nullが入る可能性のある変数を代入しようとするため、コンパイラがエラーを検出できます)
そういった時は、変数の末尾に ! を追加することで、nullではないことを明示することができます。
以下で3つのパターンについて学べます。
まずはnull許容の変数を代入するケース(couldBeNullButIsnt)。この例ではすでにnullではないことが明らかなため、そのままでもビルドが通ります。
次は、リストの中身がnull許容のケース(listThatCouldHoldNulls)。このケースでは、リストの先頭の値(listThatCouldHoldNulls.first)をnull非許容の変数に代入しようとしています。この場合、リストの中身はnullとなっている可能性があるため、末尾に ! を記載しないと代入不可(ビルドエラー)となります。
3つ目は、関数の戻り値がnull許容のケースです。この例では、その戻り値の絶対値(couldReturnNullButDoesnt().abs())を扱おうとしています。戻り値であるcouldReturnNullButDoesnt()はnullの可能性があるため、その後ろに ! を記載し、そこから絶対値を意味するabs関数を呼び出すことで代入が可能となっています。
int? couldReturnNullButDoesnt() { return -3; } void main() { int? couldBeNullButIsnt = 1; List<int?> listThatCouldHoldNulls = [2, null, 4]; int a = couldBeNullButIsnt; // すでに値が代入されているため、このケースでは!がなくてもビルドが通る int b = listThatCouldHoldNulls.first!; // リストの1番目を返す int c = couldReturnNullButDoesnt()!.abs(); // 絶対値を返す print('a is $a.'); print('b is $b.'); print('c is $c.'); }
注意点として、!を扱う場合は本当にnullではないケースにする必要があります。これを守らないと、ビルドでは検出できないnullアクセスが発生し、プログラムがクラッシュする恐れがあります。
lateキーワード
変数の中には、nullは許容しないけど、後から値を代入したい(初期化時点では値が明確ではない)ケースがあると思います。こういったケースでは、lateと呼ばれるものを使って対処できます。
lateを使う場合は、以下のように扱われます
- その変数にはまだ値を割り当てないでください
- 後で必ず値を割り当てます
- 変数を使用する場合は、変数に値が入っていることを確認するようにしてください
以下の例では、Mealクラスのコンストラクタを呼び出したあとに、descriptionに値を代入するケースです。_descriptionの宣言時、先頭にlateをつけることで、nullは許容しないが後で代入しますよ、ということを明示することができます。
上に記載したとおり、このlateがついた変数を扱う場合は、値が代入されているかを確認しましょう。以下の例では確認していないので、”myMeal.description = ‘Feijoada!’;”の行を削除して実行するとエラーが発生します。
class Meal { 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); }
最後に
今回はNull Safetyの紹介から、Null許容型の扱いかた、late の使い方について説明しました。
コードを書く際は、null safetyに従った開発が当然安全ではありますが、nullアサーション演算子などを駆使してnull許容型をうまく扱うことも今後必要になってくると思います。
Have a safe code! ってな感じで締めたいと思います。
コメントを残す