使用 Arrow 创建具有错误处理的对象构建器 - 模式匹配多个 Either
Posted
技术标签:
【中文标题】使用 Arrow 创建具有错误处理的对象构建器 - 模式匹配多个 Either【英文标题】:Creating an object builder with error handling using Arrow - Pattern match multiple Eithers 【发布时间】:2022-01-15 02:37:01 【问题描述】:我有课A
:
class A (private var z: String, private var y: String, private var x: Int)
我想为它创建一个故障安全构建器。构建器应返回Either
异常列表(例如,当缺少值时)或创建的值。 创建这样的东西的推荐方法是什么?或者有什么概念上更好的方法?
我自己的处理方法:
sealed class ABuilderException
object MissingXValue : ABuilderException()
object MissingYValue : ABuilderException()
object MissingZValue : ABuilderException()
import arrow.core.Either
import arrow.core.Option
import arrow.core.none
import arrow.core.some
class ABuilder
private var x : Option<Int> = none()
private var y : Option<String> = none()
private var z : Option<String> = none()
fun withX(x : Int) : ABuilder
this.x = x.some();
return this;
fun withY(y : String) : ABuilder
this.y = y.some();
return this;
fun withZ(z : String) : ABuilder
this.z = z.some();
return this;
fun build() : Either<A, List<ABuilderException>>
var xEither = x.toEither ABuilderException.MissingXValue
var yEither = y.toEither ABuilderException.MissingYValue
var zEither = z.toEither ABuilderException.MissingZValue
// If all values are not an exception, create A
// otherwise: Return the list of exceptions
我怎样才能最好地完成build
代码?
我赞成一种避免深度嵌套(例如orElse
或类似方法)并避免重复值(例如通过重新创建元组)的解决方案,因为这可能会导致拼写错误并使以后添加/删除属性变得更加困难。
【问题讨论】:
【参考方案1】:首先你需要将build
的签名改为:
fun build() : Either<List<ABuilderException>, A>
这样做的原因是因为Either
是右偏的——map
、flatMap
等函数在Right
值上运行,并且在值为Left
的情况下是无操作的。
要组合Either
值,您可以使用zip
:
val e1 = 2.right()
val e2 = 3.right()
// By default it gives you a `Pair` of the two
val c1 = e1.zip(e2) // Either.Right((2, 3))
// Or you can pass a custom combine function
val c2 = e1.zip(e2) two, three -> two + three // Either.Right(5)
但是这里有一个问题,如果出现错误(其中一个是Left
),它会很快失败并且只给你第一个。
我们可以使用Validated
来累积错误:
val x = none<Int>()
val y = none<String>()
val z = none<String>()
// Validated<String, Int>
val xa = Validated.fromOption(x) "X is missing"
// Validated<String, String>
val ya = Validated.fromOption(y) "Y is missing"
// Validated<String, String>
val za = Validated.fromOption(z) "Z is missing"
xa.toValidatedNel().zip(
ya.toValidatedNel(),
za.toValidatedNel()
) x, y, z -> TODO()
Validated
,就像Either
有一个zip
用于组合值的函数。不同之处在于Validated
会累积错误。在 lambda 中,您可以访问 有效 值(Int
、String
、String
)并且可以创建有效对象。
toValidatedNel()
这里从Validated<String, String>
转换为Validated<Nel<String>, String>
,其中Nel
是一个不能为空的列表。将错误累积为 List
很常见,因此它是内置的。
有关更多信息,您可以查看文档中的Error Handling tutorial。
【讨论】:
谢谢,解决了。您的解释很有帮助和教育意义!以上是关于使用 Arrow 创建具有错误处理的对象构建器 - 模式匹配多个 Either的主要内容,如果未能解决你的问题,请参考以下文章