Null許容型をunwrapしたい

Null許容型をnon-nullableな型のメソッドの引数にわたすとき困ることがある。

fun f(foo: Foo) {  }

var foo: Foo? =  
fun g() {
  f(foo) // コンパイルエラー
}

メソッドfの引数はNull許容型ではないので、Foo?型の変数を引数に書くとコンパイルエラーとなる。

if文でnullチェックしつつ早期リターン

メソッド外部で変更されない変数であれば、if文でnullチェックすると文脈から推論されてunwrapされる。

fun f(foo: Foo) {  }

var foo: Foo? = 
fun g() {
  if (foo == null) {
    return 
  }
  // foo が null のときはここには来ないのでここでは foo は Foo と推論される
  f(foo) // コンパイルエラーにならない
}

elvis演算子を利用した早期リターン

elvis演算子を使ってval 新しい変数 = 変数 ?: returnとすると変数がnullの場合は returnされるので、新しい変数に入る値はnullではない。

そのため新しい変数の型はunwrapされてNull許容型ではななくなる。

fun f(foo: Foo) {  }

var foo: Foo? = 
fun g() {
  // foo が null なら return. null でないなら新たに foo に代入→新たなfooの型はFoo
  val foo = foo ?: return 

  f(foo) // コンパイルエラーにならない
}

elvis演算子を利用してデフォルト値を設定

elvis演算子を使ってnullならデフォルト値を入れるようにしておけばNull許容型ではなくなる。

fun f(foo: Foo) {  }

var foo: Foo? = 
fun g() {
  // foo が null ならデフォルト値を入れておく
  val foo = foo ?: Foo()

  f(foo) // コンパイルエラーにならない
}

?.演算子+スコープ関数

?.演算子でnull安全にスコープ関数を呼び出すと、スコープ関数に渡した無名関数の引数がNull許容型ではなくなる。

fun f(foo: Foo) {  }

var foo: Foo? = 
fun g() {
  // foo が null なら return. null でないなら新たに foo に代入→新たなfooの型はFoo
  foo?.let { foo ->
    // 無名関数の引数fooの型はFoo
    f(foo) // コンパイルエラーにならない
  }
}