有什么理由使用暂停乐趣fn(...):要么<可扔,A>而不是暂停乐趣fn(...):A?

  • 本文关键字:fn 暂停 要么 理由 可扔 kotlin arrow-kt
  • 更新时间 :
  • 英文 :


我正在考虑一些关于suspend的事情,Arrow的文档详细解释了:suspend () -> A提供与IO<A>相同的保证。

因此,根据文档,仅使用suspend,我们将不纯函数转换为纯函数:

不洁净的

fun log(message: String): Unit = println(message)
fun main(): Unit { 
log("Hey!")
}
>
suspend fun log(message: String): Unit = println(message)
fun main(): Unit = runBlocking { 
log("Hey!")
}

仅仅添加suspend就把函数变成纯函数的事实令人惊讶,但在文档中有明确的解释。

考虑到这一点,我的下一个疑问与可能导致错误(Throwable)或值A的业务服务建模有关。

到目前为止,我一直在做这样的事情:

suspend fun log(message: String): Either<Throwable, Unit> = either { println(message) }
suspend fun add(sum1: Int, sum2: Int): Either<Throwable, Int> = either { sum1 + sum2 }
suspend fun main() {
val program = either<Throwable, Unit> {
val sum = add(1, 2).bind()
log("Result $sum").bind()
}
when(program) {
is Either.Left -> throw program.value
is Either.Right -> println("End")
}
}

但是,考虑到suspend fun fn() : A是纯的并且等价于IO<A>,我们可以将上面的程序重写为:

suspend fun add(sum1: Int, sum2: Int): Int = sum1 + sum2
suspend fun log(message: String): Unit = println(message)
fun main() = runBlocking {
try {
val sum = add(1, 2)
log("Result $sum")
} catch( ex: Throwable) {
throw ex
}
}

是否有理由选择suspend fun fn(...): Either<Throwable, A>而不是挂起fun fn(...): A?

如果你想使用Throwable,有2个选项,kotlin.Resultarrow.core.Either

差异最大的是runCatchingEither.catch。其中runCatching将捕获所有异常,而Either.catch将只捕获非致命异常。所以Either.catch会防止你不小心吞下kotlin.coroutines.CancellationException

您应该将上面的代码更改为以下代码,因为either { }不会捕获任何异常。

suspend fun log(message: String): Either<Throwable, Unit> =
Either.catch { println(message) }
suspend fun add(sum1: Int, sum2: Int): Either<Throwable, Int> =
Either.catch { sum1 + sum2 }

是否有理由选择suspend fun fn(…):Either<Throwable,>over suspend fun(…):A?

是的,在返回类型中使用ResultEither的原因将是强制调用者解决错误。强制用户解决错误,即使在IO<A>suspend中,仍然是有价值的,因为最后的try/catch是可选的。

但是使用Either来跟踪整个业务领域的错误变得非常有意义。或者用一种类型的方式跨层解析。

例如:

data class User(...)
data class UserNotFound(val cause: Throwable?)
fun fetchUser(): Either<UserNotFound, User> = either {
val user = Either.catch { queryOrNull("SELECT ...") }
.mapLeft { UserNotFound(it) }
.bind()
ensureNotNull(user) { UserNotFound() }
}

相关内容

  • 没有找到相关文章

最新更新