kotlin–result
安装
repositories {
mavenCentral()
}
dependencies {
implementation( \" com.michael-bull.kotlin-result:kotlin-result:2.0.1 \" )
}
介绍
在功能编程中, Result类型是具有返回值或错误的单声道类型。
要指示成功的操作,请返回具有成功value的Ok(value) 。如果失败,请返回带有导致故障的error的Err(error) 。
这有助于定义一条清晰/不愉快的执行道路,该执行方式通常称为面向铁路的编程,从而将快乐和不愉快的道路表示为单独的铁路。
开销
Result类型被建模为内联值类。这可以在快乐的道路上实现零对象分配。
台式设计文档中提供了带有示例输出Java代码的完整故障。
乘法支持
kotlin-result针对Kotlin/本地目标支持概述的所有三个层
阅读更多
以下是该库主题撰写的视频和文章的集合。如果您想包括您的,请随时在Github上打开拉动请求。
- [en]结果monad-亚当·贝内特(Adam Bennett)
- [en]一种功能性处理方法 – 特里斯坦·汉密尔顿(Tristan Hamilton)
- [en] Kotlin:功能性金矿-Mark Bucciarelli
- [EN]面向铁路的编程-Scott Wlaschin
- [JP] Kotlinで结果型使うならkotlin-resultを使おう
- [JP] Kotlinのコードに返回结果を组み込む
Wiki上可以使用映射,以帮助使用其他语言的Result类型的经验来帮助那些:
- 榆树
- 哈斯克尔
- 锈
- Scala
入门
以下是一个简单的示例,说明如何使用Result类型来建模可能失败的函数。
fun checkPrivileges ( user : User , command : Command ): Result < Command , CommandError > { return if (user.rank >= command.minimumRank) { Ok (command) } else { Err ( CommandError . InsufficientRank (command.name)) } }
当可能会引发异常的控件外的代码交互时,请用runCatching包裹呼叫以捕获其执行Result<T, Throwable> :
val result : Result < Customer , Throwable > = runCatching { customerDb.findById(id = 50 ) // could throw SQLException or similar }
可以使用toResultOr扩展功能将可无效的类型(例如下面示例中的find方法)转换为Result 。
val result : Result < Customer , String > = customers .find { it.id == id } // returns Customer? .toResultOr { \" No customer found \" }
转换结果
成功和故障结果都可以在铁路轨道的阶段进行转换。下面的示例演示了如何将内部程序错误转换为裸露的客户端错误IncorrectPassword UnlockError
val result : Result < Treasure , UnlockResponse > = unlockVault( \" my-password \" ) // returns Result<Treasure, UnlockError> .mapError { IncorrectPassword } // transform UnlockError into IncorrectPassword
链接
可以链接结果以产生执行的“快乐之路”。例如,用户输入命令进入管理控制台的快乐路径将包含:命令已被标记,注册命令,用户具有足够的特权以及执行相关操作的命令。下面的示例使用了我们之前定义的checkPrivileges函数。
tokenize(command.toLowerCase())
.andThen(::findCommand)
.andThen { cmd -> checkPrivileges(loggedInUser, cmd) }
.andThen { execute(user = loggedInUser, command = cmd, timestamp = LocalDateTime .now()) }
.mapBoth(
{ output -> printToConsole( \" returned: $output \" ) },
{ error -> printToConsole( \" failed to execute, reason: ${error.reason} \" ) }
)
绑定(单调理解)
binding函数允许多个调用,每个调用每个返回Result都必须束缚。当在binding块内部时,可以在任何Result上访问bind()函数。每个bind的呼叫都将尝试解开Result并存储其值,如果Result是错误的,请尽早返回。
在下面的示例中, functionX()返回错误,然后执行将跳过functionY()和functionZ() ,而是将来自functionX的错误存储在命名sum的变量中。
fun functionX (): Result < Int , SumError > { .. . } fun functionY (): Result < Int , SumError > { .. . } fun functionZ (): Result < Int , SumError > { .. . } val sum : Result < Int , SumError > = binding { val x = functionX().bind() val y = functionY().bind() val z = functionZ().bind() x + y + z } println ( \" The sum is $sum \" ) // prints \"The sum is Ok(100)\"
binding函数主要从BOW的binding功能中汲取灵感,但是下面是关于MONAD综合主题的其他资源列表。
- 单元综合 – 箭头(kotlin)
- 单调综合 – 弓(Swift)
- 用于综合-Scala
Coroutine结合支持
在coroutineBinding块中使用暂停功能需要额外的依赖性:
dependencies {
implementation( \" com.michael-bull.kotlin-result:kotlin-result:2.0.1 \" )
implementation( \" com.michael-bull.kotlin-result:kotlin-result-coroutines:2.0.1 \" )
}
coroutineBinding功能在coroutineScope内部运行,从而有助于同时进行工作分解。
当块内部的任何调用bind()失败时,范围会失败,取消所有其他孩子。
下面的示例展示了一个计算昂贵的功能,该功能需要五毫秒才能计算一旦较小的功能失败,只需一毫秒即可消失:
suspend fun failsIn5ms (): Result < Int , DomainErrorA > { .. . } suspend fun failsIn1ms (): Result < Int , DomainErrorB > { .. . } runBlocking { val result : Result < Int , BindingError > = coroutineBinding { // this creates a new CoroutineScope val x = async { failsIn5ms().bind() } val y = async { failsIn1ms().bind() } x.await() + y.await() } // result will be Err(DomainErrorB) }
灵感
该图书馆的灵感来自其他语言,其中单调存在,其中包括:
- 榆树
- 哈斯克尔
- 锈
- Scala
诸如stdlib的现有解决方案的改进包括:
- 降低了运行时开销,在快乐路径上分配零对象分配
- 功能奇偶校验与其他语言的结果类型,包括Elm,Haskell和Rust
- 对
value/error无效性的LAX限制 - 对
error类型的继承的LAX约束(不从Exception继承) - 最高级别
Ok和Err功能避免了与Result.Ok/Result.Err合格用法。 - 高阶函数标记为减少运行时开销的
inline关键词 - 扩展功能在
Iterable和List上用于折叠,组合,分区 - 与其他语言的现有结果库保持一致(例如
map,mapError,mapBoth,mapEitherand,andThen,or,orElse,unwrap) - 涵盖每个图书馆方法的近100个单位测试的广泛测试套件
例子
该示例模块包含Scott示例应用程序的实现,该应用程序在现实世界中演示了Result的用法。
它在带有A /customers端点的端口9000上托管KTOR服务器。端点响应带有提供的id的GET和POST请求,例如/customers/100 。将42的客户ID升级为硬编码,以抛出SQLException ,以说明Result类型如何将内部程序错误映射到更合适的面向用户的错误。
贡献
欢迎在GitHub上进行错误报告和拉动请求。
执照
该项目可根据ISC许可条款获得。有关版权信息和许可条款,请参见LICENSE文件。
