Contents
Snippet 1: Introducing non-nullable types
DartPadのヌルセーフティバージョンへようこそ!
これは、nullの安全性のための新しい構文とコーディングパターンを説明するために設計された一連のコード例の最初のものです。
各スニペットは、不良または壊れた状態で始まります。
Dartアナライザーからの警告が表示され、コードがコンパイルされない可能性があります。
しかし、指示に従い、コードを編集することで、
各スニペットを動作状態に更新できます。
その過程で、nullの安全性について学びます!
この最初の例は、基本的なものです。
以下の変数 `a`は` int`として宣言されています。
Dartプロジェクトでnullセーフティが有効になっている場合、デフォルトではすべての型がnon-nullable型です。
割り当ての値を3または145に変更してみてください。
null以外のもの!
void main() { int a; a = 24; print('a is $a.'); //24 }
Snippet 2:Nullable types
null値を保持できる変数が必要な場合はどうなりますか?
タイプの最後に疑問符を追加することで、null許容(null可型、nullable型)として宣言できます。
この場合、 `int?`を試してください。
void main() { int? a; a = null; print('a is $a.'); // a is null }
Snippet 3:More nullable types!
ジェネリックスの型パラメーターは、null許容または非null許容にすることもできます。 疑問符(?)を使用して、 `aNullableListOfStrings`と` aListOfNullableStrings`の型宣言を修正してみてください。
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.'); } /* aListofStrings is [one, two, three]. aNullableListOfStrings is null. aListofNullableStrings is [one, null, three]. */
Snippet 4: Definite assignment
Dartの型システムは、変数が割り当てられている場所とその値が読み取られている場所を追跡し、コードが読み取ろうとする前にnull許容でない(non-nullableな)フィールドに(nullでない)値がセットされていることを確認することができます。
このプロセスは「明確な割り当て(Definite assignment)」と呼ばれます。
以下のコードのif-elseステートメントのコメントを解除して、アナライザーのエラーが消えるのを確認してください。
void main() { String text; if (DateTime.now().hour < 12) { text = "It's morning! Let's make aloo paratha!"; } else { text = "It's afternoon! Let's make biryani!"; } print(text); print(text.length); } /* It's morning! Let's make aloo paratha! 38 */
if-else文がコメントアウトされた状態だと、
The non-nullable local variable 'text' must be assigned before it can be used
上記のエラーが出る。上記サンプルから言えることは、
non-nullable型の変数宣言時に絶対初期化しないといけない訳ではない(ローカル変数の場合)。変数が参照されるまでにnull以外の値がセットされればOK。
Definite assignmentの機能があるからそれが実現できている、ということが言いたいのだと思われる。
Snippets 5:Conditional access
Conditional access(条件付きアクセス)は、nullになる可能性のあるプロパティを読み取る必要があるコードを強化するための便利な方法です。
a?.b
上記の式は、 `a`がnullでない限り、` b`の値に評価されます。 `a`がnullの場合、式はnullと評価されます。
このコードを修正するには、条件付きアクセスを使用してみてください。
class BigThing { LittleThing little = LittleThing(); } class LittleThing { int fetchInt() => 12; } void main() { final BigThing? big = BigThing(); print('The value is:'); print(big?.little.fetchInt()); } /* The value is: 12 */
null-safety導入前は、二つのconditional access operator( ? )が必要でした。(一つはbigの後、もう一つはlittleの後)
null-safety導入後はconditional accessはshort-circuitです。
ですから、この式では一つの`?`を上記のように記述すればいいんです。
Snippets 6: Promotion
null-safety導入後は、Dartはnullチェックを考慮してくれます。
nullを含めることができない可能性のあるNULL可能変数は、NULL不可変数のように扱われます。
この挙動は“promotion“と呼ばれます。
promotion:昇進、進級、助長、振興、奨励、販売促進
下記のサンプルで、getLength関数の最初に、`str`がnullの場合0(zero)を返すif文を記述してください。
int getLength(String? str) { // Add null check here if(str==null){ return 0; } return str.length; } void main() { print(getLength('This is a string!')); } /* 17 */
この説明だけでははっきりわからないが、if文など(少なくともif文)でnullでないことをチェックしている場合、その後の文脈でnullでないことが確定する箇所はnon-nullable型として扱う、みたいなことか?
int getLength(String? str) { // Add null check here /* if(str==null){ return 0; } */ return str.length; } void main() { print(getLength('This is a string!')); } /* error An expression whose value can be 'null' must be null-checked before it can be dereferenced nullable型の式(str)は参照する前に必ずnullチェックしないといけません。 */
試しに↑のようにするとエラーが出る。if文でnullチェックしたあとはエラーがでなくなるのでやはりそういうことだと思われる。
確かUnderstanding null safety:に詳しい説明があったような気がする。
Snipetts 7: Promotion with exceptions
return文と同様に、promotionは例外(exception)といっしょに使うこともできます。
0を返す代わりに、nullチェックで例外(exception)をスロー(throw)してみましょう。
int getLength(String? str) { // Try throwing here if `str` is null. if(str==null){ throw Exception("引数にnullが渡されました。"); } return str.length; } void main() { try{ print(getLength(null)); }catch(e){ print(e); } }
このサンプルでもnullチェックで例外がスローされるので、
str.length
のstrがnullである可能性は無い。
なのでpromotionによりstrはnon-nullable型として扱われる。
したがってstr.lengthを参照してもエラーが出ない。
「nullチェックによりnullの可能性が無い箇所でnon-nullable型として扱われる、なのでdereferenceが可能になる。」これがpromotion。
参考
https://nullsafety.dartpad.dev/
の右上のメニュー(Learn with Snippets!)