🐱

Sound null safetyの扱い方

2021/11/04に公開

どのバージョンから?

Dart 2.12

何がnull safetyになる?

今まで通りに型を書くと自動でnon nullableになる。型?で書くとnullableになる。
例)

int a; //non nullable 
int? b://nullable

nullの扱いはどう変わった?

今までは、nullはNull型で全ての型の派生型だったが、null safetyになってNull型は単純に独立したNull型になった(Object型の派生型でも無い)。今までのNull型に当たるのはNever型になった(全ての型&Nullの派生型)。

int?はどういう定義?

int?はint | Nullの共用型。これによりnullを代入できる。

intとint?の変換は?

nonnullableからnullableへはOK。逆はダメ。

  int nonnullable = 1;
  int? nullable;
  
  //nonnullable = nullable;//これはダメ
  nullable = nonnullable;//これはOK

int?からintへ変換できないの?

nullableの変数名に!を付けると変換できる。その代わりnullで無い事はプログラマーが保証しないといけない(nullだったら実行時エラー)。

  int nonnullable = 1;
  int? nullable;
  
  nonnullable = nullable!;//nullableは実際にnullなので実行するとエラー

int?はnullチェックどうするの?

nullチェックしないでnullable変数を触ろうとすると構文エラーになる。nullチェックを入れれば触れる。

  int? nullable;
  
  //nullable.abs(); //nullチェック入れてないのでエラー

if文でチェックしているので.アクセスでOK

  if(nullable != null){
    print('nullable = ' + nullable.abs().toString());
  }else{
    print('nullable is null');
  }

if文チェックでreturnしているので.アクセスでOK

  if(nullable==null)return;  
  nullable.abs();

null-aware operatorsによるチェック

  //?.でチェック
  nullable?.abs();
  
  //??でチェック
  print('nullable = ' + (nullable ?? 1).abs().toString());

Neverを使ったチェック。

void throwException(){
  throw Exception('Exception');
}

という例外を返す関数がある場合に

  if(nullable==null)throwException();  
  nullable.abs();//エラー

だとnullable.abs()が実行される時はnullじゃない事が確実だが、構文解釈時には判断できずにエラーになる。その関数で処理が終わる(or例外で止まる)場合は、voidでは無くNeverを戻り値に指定するようにすると構文解釈時に判断出来てエラーでは無くなる。

Never throwException(){
  throw Exception('Exception');
}

if(nullable==null)throwException();  
nullable.abs();//OK

クラスのプロパティはif文のnullチェック効かないよ

class A{
  int? val;
}

void main() {
  A a = A();
  
  if(a.val != null){
    print('a.val.abs()=' + a.val.abs());  //nullチェックしているのにダメ
  }
}

この場合は一旦ローカル変数に代入して、そのローカル変数をnullチェックして使う

  int? nonnullable = a.val;
  if(nonnullable != null){
    print('a.val.abs()=' + nonnullable.abs().toString());
  }

参考:
Sound null safety
Understanding null safety

Discussion