Kotlin Result 类型扩展详解 —— 新手使用指南

Result 是 Kotlin 标准库中用于封装成功或失败结果的类型,特别适合函数式错误处理。本文将详细扩展 Result 的各种使用场景,包括依赖关系、选择关系和对协程的支持。

一、基本 Result 使用

首先回顾基本用法:

kotlin 复制代码
fun divide(a: Int, b: Int): Result<Int> {
    return if (b == 0) {
        Result.failure(ArithmeticException("Division by zero"))
    } else {
        Result.success(a / b)
    }
}

fun main() {
    val result = divide(10, 2)
    result.onSuccess { println("Result: $it") }
          .onFailure { println("Error: ${it.message}") }
}

二、依赖关系处理

2.1 一对一依赖(线性依赖)

kotlin 复制代码
// 一个操作依赖于前一个操作的结果
fun processUserData(userId: String): Result<String> {
    return fetchUser(userId)
        .flatMap { user -> validateUser(user) }
        .map { validUser -> formatUserData(validUser) }
}

private fun fetchUser(id: String): Result<User> {
    return if (id.isNotEmpty()) Result.success(User(id, "John")) 
           else Result.failure(IllegalArgumentException("Invalid ID"))
}

private fun validateUser(user: User): Result<User> {
    return if (user.name.isNotEmpty()) Result.success(user)
           else Result.failure(IllegalArgumentException("Invalid user"))
}

private fun formatUserData(user: User): String {
    return "User: ${user.name} (ID: ${user.id})"
}

data class User(val id: String, val name: String)

fun main() {
    processUserData("123").fold(
        onSuccess = { println(it) },
        onFailure = { println("Error: ${it.message}") }
    )
}

2.2 一对多依赖(一个操作依赖多个独立操作)

kotlin 复制代码
// 多个独立操作,全部成功才能继续
fun processOrder(orderId: String, userId: String): Result<OrderResult> {
    return Result.runCatching {
        val user = fetchUser(userId).getOrThrow()
        val order = fetchOrder(orderId).getOrThrow()
        val inventory = checkInventory(order.items).getOrThrow()
        
        OrderResult(user, order, inventory)
    }
}

// 模拟其他函数
private fun fetchOrder(id: String): Result<Order> = Result.success(Order(id, listOf("item1", "item2")))
private fun checkInventory(items: List<String>): Result<Boolean> = Result.success(true)

data class Order(val id: String, val items: List<String>)
data class OrderResult(val user: User, val order: Order, val hasInventory: Boolean)

fun main() {
    processOrder("order123", "user123").fold(
        onSuccess = { println("Order processed: $it") },
        onFailure = { println("Failed to process order: ${it.message}") }
    )
}

2.3 多对一依赖(多个操作可以独立失败)

kotlin 复制代码
// 多个操作,收集所有结果(成功或失败)
fun collectMultipleResults(): Result<List<Result<Any>>> {
    val results = listOf(
        fetchUser("1"),
        fetchProduct("p1"),
        fetchSettings("s1")
    )
    return Result.success(results)
}

// 或者只关心成功的部分
fun collectSuccessfulResults(): List<Any> {
    return listOf(
        fetchUser("1"),
        fetchProduct("p1"),
        fetchSettings("s1")
    ).filter { it.isSuccess }.map { it.getOrNull()!! }
}

// 模拟函数
private fun fetchProduct(id: String): Result<Product> = Result.success(Product(id))
private fun fetchSettings(id: String): Result<Settings> = Result.failure(IllegalStateException("Settings unavailable"))

data class Product(val id: String)
data class Settings(val config: String)

fun main() {
    println("All results:")
    collectMultipleResults().getOrThrow().forEach { println(it) }
    
    println("\nSuccessful results:")
    println(collectSuccessfulResults())
}

三、选择关系(替代方案)

kotlin 复制代码
// 尝试多个操作,使用第一个成功的
fun findAlternativeResource(): Result<String> {
    return fetchPrimaryResource()
        .recoverCatching { fetchSecondaryResource().getOrThrow() }
        .recoverCatching { fetchFallbackResource().getOrThrow() }
}

// 或者更简洁的写法
fun findAlternativeResource2(): Result<String> {
    return listOf(
        { fetchPrimaryResource() },
        { fetchSecondaryResource() },
        { fetchFallbackResource() }
    ).firstSuccess()
}

// 扩展函数:获取第一个成功的Result
fun <T> List<() -> Result<T>>.firstSuccess(): Result<T> {
    for (operation in this) {
        operation().onSuccess { return Result.success(it) }
    }
    return Result.failure(IllegalStateException("All operations failed"))
}

// 模拟函数
private fun fetchPrimaryResource(): Result<String> = Result.failure(IOException("Primary unavailable"))
private fun fetchSecondaryResource(): Result<String> = Result.failure(IOException("Secondary unavailable"))
private fun fetchFallbackResource(): Result<String> = Result.success("Fallback data")

fun main() {
    findAlternativeResource().fold(
        onSuccess = { println("Resource: $it") },
        onFailure = { println("All attempts failed: ${it.message}") }
    )
    
    findAlternativeResource2().fold(
        onSuccess = { println("Alternative resource: $it") },
        onFailure = { println("All alternatives failed: ${it.message}") }
    )
}

四、Result 集合处理

kotlin 复制代码
// 处理Result集合的几种方式

// 1. 全部成功才成功
fun processAllOrFail(results: List<Result<Int>>): Result<List<Int>> {
    return results.fold(Result.success(emptyList())) { acc, result ->
        acc.flatMap { list -> result.map { list + it } }
    }
}

// 2. 收集所有结果(成功和失败分开)
data class PartitionedResults<T>(val successes: List<T>, val failures: List<Throwable>)

fun <T> partitionResults(results: List<Result<T>>): PartitionedResults<T> {
    return results.fold(PartitionedResults(emptyList(), emptyList())) { acc, result ->
        result.fold(
            onSuccess = { acc.copy(successes = acc.successes + it) },
            onFailure = { acc.copy(failures = acc.failures + it) }
        )
    }
}

// 3. 只收集成功的
fun <T> getAllSuccesses(results: List<Result<T>>): List<T> {
    return results.mapNotNull { it.getOrNull() }
}

fun main() {
    val results = listOf(
        Result.success(1),
        Result.failure(RuntimeException("Error 1")),
        Result.success(2),
        Result.failure(IllegalStateException("Error 2")),
        Result.success(3)
    )
    
    println("All or nothing:")
    println(processAllOrFail(results))
    
    println("\nPartitioned:")
    println(partitionResults(results))
    
    println("\nOnly successes:")
    println(getAllSuccesses(results))
}

五、协程支持

kotlin 复制代码
import kotlinx.coroutines.*
import java.io.IOException

// 协程中的Result使用
suspend fun fetchUserData(userId: String): Result<String> = withContext(Dispatchers.IO) {
    Result.runCatching {
        // 模拟网络请求
        delay(1000)
        if (userId == "error") throw IOException("Network error")
        "Data for $userId"
    }
}

suspend fun fetchUserProfile(userId: String): Result<String> = withContext(Dispatchers.IO) {
    Result.runCatching {
        delay(500)
        if (userId == "invalid") throw IllegalStateException("Invalid user")
        "Profile of $userId"
    }
}

// 并行获取多个数据
suspend fun fetchMultipleData(userId: String): Result<Pair<String, String>> = coroutineScope {
    val deferredData = async { fetchUserData(userId) }
    val deferredProfile = async { fetchUserProfile(userId) }
    
    val dataResult = deferredData.await()
    val profileResult = deferredProfile.await()
    
    if (dataResult.isSuccess && profileResult.isSuccess) {
        Result.success(Pair(dataResult.getOrThrow(), profileResult.getOrThrow()))
    } else {
        val exceptions = listOfNotNull(
            dataResult.exceptionOrNull(),
            profileResult.exceptionOrNull()
        )
        Result.failure(exceptions.firstOrNull() ?: Exception("Unknown error"))
    }
}

// 使用recoverWith处理异步错误
suspend fun fetchWithFallback(userId: String): Result<String> {
    return fetchUserData(userId)
        .recoverCatching { fetchUserProfile(userId).getOrThrow() }
}

fun main() = runBlocking {
    println("Successful case:")
    fetchMultipleData("123").fold(
        onSuccess = { println(it) },
        onFailure = { println("Error: ${it.message}") }
    )
    
    println("\nError case:")
    fetchMultipleData("error").fold(
        onSuccess = { println(it) },
        onFailure = { println("Error: ${it.message}") }
    )
    
    println("\nRecovery case:")
    fetchWithFallback("error").fold(
        onSuccess = { println("Fetched: $it") },
        onFailure = { println("Failed: ${it.message}") }
    )
}

六、实用扩展函数

kotlin 复制代码
// 一些有用的Result扩展函数

// 将多个Result合并为一个
fun <T1, T2> Result<T1>.combine(other: Result<T2>): Result<Pair<T1, T2>> {
    return this.flatMap { t1 -> other.map { t2 -> t1 to t2 } }
}

// 将List<Result<T>>转换为Result<List<T>>
fun <T> List<Result<T>>.sequence(): Result<List<T>> {
    return this.fold(Result.success(emptyList())) { acc, result ->
        acc.flatMap { list -> result.map { list + it } }
    }
}

// 过滤成功的Result
fun <T> List<Result<T>>.filterSuccess(): List<T> {
    return this.mapNotNull { it.getOrNull() }
}

// 执行副作用并返回原始Result
fun <T> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
    this.onSuccess { action(it) }
    return this
}

fun <T> Result<T>.onFailure(action: (Throwable) -> Unit): Result<T> {
    this.onFailure { action(it) }
    return this
}

fun main() {
    val r1 = Result.success(1)
    val r2 = Result.success("two")
    val r3 = Result.failure<Boolean>(RuntimeException("Error"))
    
    println("Combine:")
    println(r1.combine(r2))
    println(r1.combine(r3))
    
    println("\nSequence:")
    val results = listOf(r1, r2.map { it.length }, Result.success(3.0))
    println(results.sequence())
    
    println("\nFilter success:")
    val mixedResults = listOf(r1, r2, r3)
    println(mixedResults.filterSuccess())
}

七、总结

  1. 依赖关系

    • 一对一:使用 flatMapmap 链式调用
    • 一对多:使用 runCatching 组合多个操作
    • 多对一:收集多个独立操作的结果
  2. 选择关系

    • 使用 recoverrecoverCatching 提供备用方案
    • 实现 firstSuccess 选择第一个成功的操作
  3. 集合处理

    • sequence 转换 List<Result<T>>Result<List<T>>
    • 分区处理成功和失败的结果
  4. 协程支持

    • 在挂起函数中使用 Result.runCatching
    • 并行执行多个异步操作并组合结果
  5. 扩展函数

    • 创建实用扩展函数使 Result 处理更简洁

这些模式可以帮助你在Kotlin中构建健壮的错误处理流程,特别是在复杂的异步或依赖操作场景中。

更多分享

  1. 一文吃透Kotlin中冷流(Clod Flow)和热流(Hot Flow)
  2. 一文带你吃透Kotlin协程的launch()和async()的区别
  3. Kotlin 委托与扩展函数------新手入门
  4. Kotlin 作用域函数(let、run、with、apply、also)的使用指南
  5. 一文带你吃透Kotlin中 lateinit 和 by lazy 的区别和用法
  6. Kotlin 扩展方法(Extension Functions)使用详解
  7. Kotlin 中 == 和 === 的区别
  8. Kotlin 操作符与集合/数组方法详解------新手指南
  9. Kotlin 中 reified 配合 inline 不再被类型擦除蒙蔽双眼
相关推荐
雨白7 小时前
Android 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk7 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING8 小时前
RN容器启动优化实践
android·react native
恋猫de小郭10 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker15 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴15 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农2 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos