この記事を読むのに必要な時間は約 13 分です。
この記事ではDart におけるNullsafety とその使い方について説明します
・Dart の型はデフォルトでnull を許容しない。
・型の後ろに? を付けることでnull 許容することができるが、メソッド、関数、値の代入時など注意が必要。
Nullsafety とは
①Nullsafety とは
「Nullsafety 」に対応しているとは、デフォルトで型がnull を許容しないという意味です。
※ null とは何もない状態、例えば変数に何も代入されていないような状態を指します。
Dart 2.12 & Flutter 2. 以降ではNullsafety に対応しています。これはAPIでnon-nullが圧倒的に多かったかららしいです。
下記の例ではNullsafety によりint 型はnon-nullable な型 (null を許容しない型)のためエラーが起きます。
void main() { int a; // int はnon-nullable な型 a = null; print('a is $a.'); // エラー }
エラー内容
A value of type ‘Null’ can’t be assigned to a variable of type ‘int’.
Try changing the type of the variable, or casting the right-hand type to ‘int’.
Null の許容の仕方
①? を使うとnull を許容できる
型の後に? を付けることでnull の代入を許容できます。
下記の例ではint? 型はnull を許容するためエラーになりません。
void main() { int? a; // int? はnullable な型 a = null; print('a is $a.'); // console a is null }
また、ジェネリクス型でもnullable、non-nullable の使い分けはされます。
ジェネリクスについてはこちらの記事を一読ください。
下記の例ではLIst<String> とString はnon-nulable な型なのでエラーが起きます。
void main() { List<String> aListOfStrings = ['one', 'two', 'three']; List<String> aNullableListOfStrings; // LIst<String> はnon-nulable な型。 List<String> aListOfNullableStrings = ['one', null, 'three']; /// String はnon-nulable な型。 print('aListOfStrings is $aListOfStrings.'); // console aListOfStrings is 'one', 'two', 'three' print('aNullableListOfStrings is $aNullableListOfStrings.'); // aNullableListOfStringsに値を代入していないためエラー print('aListOfNullableStrings is $aListOfNullableStrings.'); // aListOfNullableStringsの第2引数は null なのでエラー }
aNullableListOfStrings はList 自体がnull なのでList<String>? とし、
aListOfNullableStrings はList の要素が一部null なのでList <String?> とすることで解決します。
void main() { List<String> aListOfStrings = ['one', 'two', 'three']; List<String>? aNullableListOfStrings; List<String?> aListOfNullableStrings = ['one', null, 'three']; print('aListOfStrings is $aListOfStrings.'); print('aNullableListOfStrings is $aNullableListOfStrings.'); print('aListOfNullableStrings is $aListOfNullableStrings.'); }
Null を許容した際の注意点
Null を許容してエラーになる例
下記の例を見て下さい。
int? couldReturnNullButDoesnt() => -3; void main() { int? couldBeNullButIsnt = 1; List<int?> listThatCouldHoldNulls = [2, null, 4]; int a = couldBeNullButIsnt; int b = listThatCouldHoldNulls.first; // first item in the list エラー int c = couldReturnNullButDoesnt().abs(); // absolute value エラー print('a is $a.'); print('b is $b.'); print('c is $c.'); }
この例ではint? 型のlistThatCouldHoldNulls の一要素目をint 型 b に代入しようとしているため、エラーになります。
また、couldReturnNullButDoesnt についてもnull が入る可能性があるので.abs() が適用できず、c はエラーになります。
このようにnull を許容した変数に対して、「null を渡せないメソッドや関数を使用する」、「null を許容しない変数を代入する」とエラーが起きます。
後述の①、②、③いずれかの対応が必要です。
①null でないことを確定させる
? で定義した変数がnull でないことが確実な場合、null断定演算子null assertion operator (!)を使用しnon-nullableであることを確定させます。
listThatCouldHoldNulls.first! 、couldReturnNullButDoesnt()! とするとnull でないことが確定されるのでエラーは消えます。
int? couldReturnNullButDoesnt() => -3; void main() { int? couldBeNullButIsnt = 1; List<int?> listThatCouldHoldNulls = [2, null, 4]; int a = couldBeNullButIsnt; int b = listThatCouldHoldNulls.first!; // first item in the list int c = couldReturnNullButDoesnt()!.abs(); // absolute value print('a is $a.'); print('b is $b.'); print('c is $c.'); }
ただし、!は例外を投げるため、null であることが明らかな場合以外は使用を避けた方がよさそうです。
Dart の公式ページでも下記のように言及しています。
If you’re wrong, Dart throws an exception at run-time. This makes the
https://dart.dev/codelabs/null-safety!
operator unsafe, so don’t use it unless you’re very sure that the expression isn’t null.
②null だった場合、何を入れるかを ?? で指定する
「nullでない場合の処理 ?? nullの場合の処理 」という形で場合分けの処理ができます。
つまり、下記のようにしてもエラーを回避することが可能です。
int? couldReturnNullButDoesnt() => -3; void main() { int? couldBeNullButIsnt = 1; List<int?> listThatCouldHoldNulls = [3, null, 4]; int a = couldBeNullButIsnt; int b = listThatCouldHoldNulls.first ?? 3; // first item in the list int c = couldReturnNullButDoesnt() ?? -3.abs(); // absolute value print('a is $a.'); print('b is $b.'); print('c is $c.'); }
③変数宣言時の型を変える
型を変えても問題ないなら下記のようにしてもエラーを取り除けます。
int couldReturnNullButDoesnt() => -3; void main() { int? couldBeNullButIsnt = 1; List<int?> listThatCouldHoldNulls = [2, null, 4]; int a = couldBeNullButIsnt; int? b = listThatCouldHoldNulls.first; // first item in the list int c = couldReturnNullButDoesnt().abs(); // absolute value print('a is $a.'); print('b is $b.'); print('c is $c.'); }
参考サイトの紹介
Codelab でNullsafety のexercise があったのでリンクを貼っておきます。ぜひ手を動かして理解を深めて下さい。
さらに詳しく知りたい場合はこちらを見てみるのが良さそうです。
以上、Dart のNullsafety についてまとめてみました!
コメント