(この記事、というかこのブログ全体で、言葉の定義として
フィールド = プロパティ
です。)
Conditional member access
nullableな変数に対して使うことで実行時エラーを防げる。
//sample_1 void main() { P? p1; int n = p1.y; //←error print('$n'); } class P{ int y=0; }
//result of sample_1 line 4 • The property 'y' can't be unconditionally accessed because the receiver can be 'null'. (view docs) Try making the access conditional (using '?.') or adding a null check to the target ('!').
sample_1では
「プロパティ’y’は無条件にアクセスできません、なぜならreceiver(参照しようとしているインスタンス、つまりp1のこと)の値がnullになる可能性があるからです。
コンディショナルにアクセスする(‘?.’を使う)か、あるいはターゲット( p1のこと)に対して(‘!’を使って)nullチェックをしてください。」
というエラーメッセージが出る。
実際sample_1ではp1の値はnullなので、p1.yはnull.yということになるが、nullのyフィールドにはアクセスできない。
Conditional member access( ?. )を使ってみる。
//sample_2 void main() { P? p1; //↓Conditional member accessを使う。 int n = p1?.y; //←error print('$n'); } class P{ int y=0; }
result of sample_2 line 4 • A value of type 'int?' can't be assigned to a variable of type 'int'. (view docs) Try changing the type of the variable, or casting the right-hand type to 'int'.
「int?型の値を、int型の変数に代入することはできません。変数(a)の型を(int?に)変更するか、右側の変数を(int?→intに)キャストしてください。」
Conditional member access( ?. )は、receiver(p1)が「nullでない」ならフィールドにアクセスする、receiver(p1)がnullなら「p1?.y全体」がnullと評価される、というもの。
(だからreceiver(p1)がnullでも実行時エラーは出ない。)
今回のサンプルで言うと、
=> p1が「nullでない」なら、p1?.yはp1のyフィールドの値
=> p1がnullなら、p1?.yはnull
と評価される。
sampel_2ではp1の値はnull(初期化されていない)なので、p1?.yはnullと評価される。
つまりp1?.yはnullになる可能性があるので、nullable型と認識(判断)される。
しかし、代入先のnはint型(non-nullable型)で宣言されているので上記のコンパイルエラーが出ている。
nをnullable型で宣言する。
//sample_3 void main() { P? p1; //↓nをnullable型で宣言 int? n = p1?.y; print('$n'); //null } class P{ int y=0; }
null (エラー無し)
nをnullble型で宣言すればnullable型の値をnullble型の変数に代入することになるので、sample_2で出ていたエラーは出なくなる。
と言うことで、
//sample3_1 void main() { P? p1; int? n; if(p1 != null){ n = p1.y; }else{ n = null; } print('$n'); // null } class P{ int y=0; }
//sample3_2 void main() { P? p1; int? n = p1 != null ? p1.y : null; print('$n'); // null } class P{ int y=0; }
sample3はsample3_1、sample3_2と同じ意味(同じ結果)となります。