sealed class Expr {
class Const(val number: Double) : Expr()
class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
Sealed classes are used for representing restricted class hierarchies,
when a value can have one of the types from a limited set, but cannot have any other type.
in a sense, an extension of enum classes
Expr
型の変数には : Const
型 / Sum
型 / NotANumber
when
式で効果を発揮values()
メソッドみたいなのはないwhen
式での使用val message = when (expr) {
is Expr.Const -> "const : " + expr.number
is Expr.Sum -> "sum : " + expr.e1 + " + " + expr.e2
is Expr.NotANumber -> "not a number"
}
when
を式として扱う場合に網羅できてないとコンパイルエラーsealed class EntryListScreenType {
sealed class Category(val categoryId: String) : EntryListScreenType() {
object It : Category("xxxx")
object Fun : Category("yyyy")
// ...
}
object MyHotEntry : EntryListScreenType()
// ...
}
when
式での使用fun createIntentFromEntryScreenType(t: EntryListScreenType) = when (t) {
is EntryListScreenType.Category ->
EntryListCategoryActivity.createIntent(this, t.categoryId)
is EntryListScreenType.MyHotEntry ->
EntryListMyHotEntryActivity.createIntent(this)
}
// 普通にやるなら起こりうる例外を検査例外にしたいところ
SuccessValue fooBar() throws Error1, Error2 { /* ... */ }
// RxJava を使う場合は例外を検査例外にできない
Observable<SucessValue /* ??? */> fooBar() { /* ... */ }
Either
みたいなものを定義すると良さそう?
(下の例がベストプラクティスだというつもりはないけど一つの例として)
// 汎用的なクラス。
sealed class Result<V, E> {
class Success<V, E>(val value: V) : Result<V, E>()
class Error<V, E>(val value: E) : Result<V, E>()
}
// あるメソッド (今回の例だと `fooBar` メソッド) が
// 返しうる例外一覧の sealed class。
sealed class FooBarException {
class E1(val value: Error1) : FooBarException()
class E2(val value: Error2) : FooBarException()
}
val o: Observable<Result<SuccessValue, FooBarException>> = fooBar()
o.subscribe({ res ->
// この `when` は文なので branch が網羅されていなくても
// コンパイルエラーにならない。
when (res) {
is Result.Success -> procOnSuccess(res.value)
is Result.Error -> {
when (res.value) {
is FooBarException.E1 -> procOnError1(res.value.value)
is FooBarException.E2 -> procOnError2(res.value.value)
}
}
}
})
when
が文でも網羅しているかチェックしてほしいwhen
式の戻り値を使うかどうかっぽいwhen (res.value) {
is FooBarException.E1 -> procOnError1(res.value.value)
is FooBarException.E2 -> procOnError2(res.value.value)
} as Unit