LoginSignup
12
3

More than 5 years have passed since last update.

contract を試してみる

Posted at

contract?

長澤太郎さんによる、とてもわかりやすいスライドがすでにあるので見てください(完)
Kotlin Contract

で、終わるわけにもいけないので、具体的に試してみたことを書いてみます。

試してみること

  • Nullableな引数を受け取って、Nullじゃないかつ、特定の状態であればtrueを返すメソッドを作成する
    • このメソッドで判定を行った場合に、trueなら NonNullな型にスマートキャストされるようにする

具体的な例

nullかもしれない曜日の文字列を受け取って、休みの日(null ではない)なら hello ${曜日} と出力する

/**
 * 渡された曜日が休日かどうかを判定する
 *
 * @param dayOfWeek: "月", "火", "水", "木", "金", "土", "日", null
 * @return true:  休日
 *         false: 休日ではない
 */
fun isHoliday(dayOfWeek: String?): Boolean {
    return when (dayOfWeek) {
        "日" -> true
        else -> false
    }
}

/** "hello ${曜日名}" を出力する */
fun helloHoliday(dayOfWeek: String) = println("hello $dayOfWeek")

// "日" を設定。ただしNullable 型としておく
val dayOfWeek: String? = "日"

if (isHoliday(dayOfWeek)) {
    // 本当はこう書きたい
    // helloHoliday(dayOfWeek)
    // が、nullチェックしてからじゃないとコンパイルエラーになるため、どこかでnullチェックが必要
    if (dayOfWeek != null) {
        helloHoliday(dayOfWeek)
    }
}

isHoliday が true を返したら null じゃないことがわかっているのに!という場合でも、helloHolidayの引数がNonNull型のため、nullチェックが必要です。
面倒くさい!なんとかしたい!

そんな時に使えるのがcontractです。

isHoliday を次のように書き換えます。

@ExperimentalContracts // contract はまだexperimental なので、annotationをつけておく必要がある
fun isHoliday(dayOfWeek: String?): Boolean {
    // コンパイラに、 true を返したら、引数はnullではないですよ、と教えてやる
    contract {
        returns(true) implies (dayOfWeek != null)
    }
    return when (dayOfWeek) {
        "日" -> true
        else -> false
    }
}

そうすると、次のような呼び出しでOKになります!

// 利用側も、どこかに@ExperimentalContracts をつけておく必要があるが今回は省略
if (isHoliday(dayOfWeek)) {
    // こう書いてもコンパイルエラーにならない!
    helloHoliday(dayOfWeek)
}

まとめ

  • nullチェック + なんらかのチェック をまとめて行う関数を利用している場合、便利に使えそう
  • ただし、まだExperimentalなので、利用する際は注意が必要
  • 日曜日しか休みがないのはバグなのでは?
12
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
3