Kotlin Academy · レッスン

SealedなResult階層

カスタムの結果型を作成します

レッスン 3/413 ステップ

「SealedなResult階層」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

組み込みResultの先へ

Kotlinの Result は、失敗時に例外しか保持できません。より豊富で型付けされたエラー情報が必要になることもよくあります。sealed class の階層を使うと、ドメインに存在する結果を正確にモデル化できます。

sealedな結果

成功とエラーのサブクラスを持つ sealed 型を定義します。コンパイラーはすべてのケースを把握できるため、網羅的な処理が可能になります。

sealed class Outcome<out T> {
    data class Ok<T>(val value: T) : Outcome<T>()
    data class Err(val message: String) : Outcome<Nothing>()
}

fun main() {
    val r: Outcome<Int> = Outcome.Ok(5)
    println(r)
}

網羅的なwhen

型が sealed なので、その型に対する when では else が不要です。コンパイラーがすべてのケースを処理していることを保証します。

sealed class Outcome<out T> {
    data class Ok<T>(val value: T) : Outcome<T>()
    data class Err(val message: String) : Outcome<Nothing>()
}

fun describe(o: Outcome<Int>) = when (o) {
    is Outcome.Ok -> "value " + o.value
    is Outcome.Err -> "error " + o.message
}

fun main() {
    println(describe(Outcome.Ok(9)))
    println(describe(Outcome.Err("boom")))
}

型付きエラーのバリエーション

異なる種類の失敗を別々のサブクラスとしてモデル化し、それぞれに関連するデータを保持させます。1つの不透明な例外にまとめるよりも優れた方法です。

sealed class Fetch<out T> {
    data class Success<T>(val data: T) : Fetch<T>()
    data class NotFound(val id: Int) : Fetch<Nothing>()
    data class Network(val code: Int) : Fetch<Nothing>()
}

fun main() {
    val r: Fetch<String> = Fetch.NotFound(42)
    println(r)
}

各バリエーションの処理

when を使うと、各エラー型に応じた処理を行えます。それぞれの分岐で、必要なデータをすべて利用できます。

sealed class Fetch<out T> {
    data class Success<T>(val data: T) : Fetch<T>()
    data class NotFound(val id: Int) : Fetch<Nothing>()
    data class Network(val code: Int) : Fetch<Nothing>()
}

fun handle(f: Fetch<String>) = when (f) {
    is Fetch.Success -> "data: " + f.data
    is Fetch.NotFound -> "missing id " + f.id
    is Fetch.Network -> "net error " + f.code
}

fun main() {
    println(handle(Fetch.Network(503)))
}

Nothingのテクニック

成功値を持たないエラーバリエーションには、Outcome<Nothing> を使用します。Nothing はすべての型のサブタイプであり、ジェネリック型が out なので、エラーを任意の Outcome<T> に適合させられます。

sealed class Res<out T> {
    data class Ok<T>(val v: T) : Res<T>()
    object Empty : Res<Nothing>()
}

fun get(flag: Boolean): Res<String> =
    if (flag) Res.Ok("hi") else Res.Empty

fun main() {
    println(get(false))
}

状態を持たないケースのobject

エラーバリエーションがデータを持たない場合は、クラスではなく object のシングルトンとして宣言します。

sealed class Login {
    data class Success(val user: String) : Login()
    object WrongPassword : Login()
    object Locked : Login()
}

fun main() {
    val r: Login = Login.WrongPassword
    println(r === Login.WrongPassword)
}

階層を返す

関数が sealed 型を返すようにすると、呼び出し側はすべての結果に対応する必要があるため、エラーパスの処理漏れをなくせます。

sealed class Parsed {
    data class Num(val value: Int) : Parsed()
    data class Bad(val input: String) : Parsed()
}

fun parse(s: String): Parsed {
    val n = s.toIntOrNull()
    return if (n != null) Parsed.Num(n) else Parsed.Bad(s)
}

fun main() {
    when (val r = parse("x")) {
        is Parsed.Num -> println(r.value)
        is Parsed.Bad -> println("bad: " + r.input)
    }
}

sealed型と組み込みResultの比較

すばやく例外ベースの捕捉を行う場合は、組み込みの Result を使用します。ドメイン固有のデータを持つ複数の型付きエラーケースと、網羅的な処理が必要な場合は、独自の sealed 階層を使用します。

階層の設計

よい sealed result の設計は次のとおりです。

  • ペイロードを保持する成功バリエーションを1つ用意する
  • 意味のある失敗の種類ごとにサブクラスを1つ用意する
  • エラーのみのケースには out T の変性と Nothing を使用する

安全網としてのコンパイラー

最大の利点は、後から新しいバリエーションを追加したときに、網羅的でない when がすべてコンパイルエラーになることです。対応が必要な場所を1つずつ示してくれるため、エラーが気付かないうちに通り抜けることはありません。

理解度チェック

sealed result 階層についての理解度を確認しましょう。

まとめ

sealed result 階層を構築しました。

  • 成功と型付きエラーのバリエーション
  • else を使わない網羅的な when
  • エラーのみのケースに対応する out T と Nothing
  • 新しいバリエーションの処理をコンパイラーが保証する仕組み

次は、map と recover を使った関数型エラー処理です。

無料で開始

AI チューターと学ぶ Kotlin — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
51
レッスン
203

よくある質問

「SealedなResult階層」レッスンは無料ですか?

はい。「SealedなResult階層」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「SealedなResult階層」で何を学びますか?

カスタムの結果型を作成します ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「SealedなResult階層」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Result型
  2. runCatching
  3. SealedなResult階層
  4. 関数型エラーハンドリング
← Kotlin Academyに戻る