🥜

エルビス演算子(?:)でnullの時の処理を書く[kotlin]

2024/08/10に公開

※※ そもそもnullかどうかで処理を分けたい場合は if elseを使った方が良さそう。特に完全な個人開発でない場合。ただ簡単な処理の場合は選択肢のひとつに入れても良いとは思うので書き残しておく。※※


?.let{} ?: run{} といったnullのときの処理も用意する場合、スコープ関数の動作を理解していないと予期せぬバグが起こる危険がある。
そこで、kotlinのスコープ関数の戻り値をコードを実行しながら動作を確認する。

戻り値の比較

本題に入る前に戻り値の比較を行う。

  • let run : ラムダ式の結果
  • also apply : オブジェクト自身

つまりletとrunは何が返ってくるか分からない。letとrunの戻り値を使いたい時は戻り値の型を定義しておくのが良さそう。

var str : String? = "kotlin"

val strLet = str?.let {
    it.uppercase()
}
println("let=$strLet") // let=KOTLIN

val strAlso = str?.also {
    it.uppercase()
}
println("also=$strAlso") // also=kotlin

この場合はletの中で文字列の変換を行った結果が返されているが、オブジェクトと全く関係ない値を返すことも可能。

val strLet = str?.let {
    it.uppercase()
    3.0f
}

この場合はstrLet: Float?ということになる。

スコープ関数とエルビス演算子の組み合わせ

  • スコープ関数にエルビス演算子?:をつけたときの動作を確認していく。

適当に文字列が空だったらnullを返す関数を用意する

fun validateTitle(title: String) : String?{
    if(title.isEmpty()) return null
    return title
}

文字列がnull出ない場合 printTitle() を実行する処理を行う

str?.スコープ関数{
    validateTitle(this)
} ?: run {
    println("error")
}

var str : String? = "" の場合の結果を見ていく

let

  • レシーバ : it
  • 戻り値 : ラムダ式の結果
str?.let{
    validateTitle(it)
} ?: run {
    println("let error") // 実行される
}

let{} の中の printTitle(it) が null のため、println("let error")実行される

run

  • レシーバ : this
  • 戻り値 : ラムダ式の結果
str?.run{
    validateTitle(this)
} ?: run {
    println("run error") // 実行される
}

run{} の中の printTitle(this) が null のため、println("run error")実行される

also

  • レシーバ : it
  • 戻り値 : オブジェクト自身
str?.also{
    validateTitle(it)
} ?: run {
    println("also error") // 実行されない
}

str は not null のため println("also error")実行されない

apply

  • レシーバ : this
  • 戻り値 : オブジェクト自身
str?.apply{
    validateTitle(this)
} ?: run {
    println("apply error") // 実行されない
}

str は not null のため println("apply error")実行されない

Discussion