使用箭头图案匹配多个Eithers创建一个具有错误处理的对象生成器



我有类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或类似方法(和避免重复值(例如通过重新创建元组(的解决方案,因为这可能会导致打字错误,并使以后更难添加/删除属性。

首先需要将build的签名更改为:

fun build() : Either<List<ABuilderException>, A>

这样做的原因是Either是右偏的——像mapflatMap等函数对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() }

ValidatedEither一样具有用于组合值的zip函数。不同之处在于Validated将累积误差。在lambda中,您可以访问有效的值(IntStringString(,并且可以创建有效的对象。

这里的toValidatedNel()Validated<String, String>转换为Validated<Nel<String>, String>,其中Nel是不能为空的列表。累积错误作为List是常见的,因此它内置于中

有关更多信息,您可以查看文档中的错误处理教程。

相关内容

  • 没有找到相关文章

最新更新