使用箭头创建具有错误处理的对象生成器 - 模式匹配多个 Eithers
Creating an object builder with error handling using Arrow - Pattern match multiple Eithers
我有 class A
:
class A (private var z: String, private var y: String, private var x: Int)
我想为它创建一个故障保护生成器。构建器应该 return 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
或类似方法)并避免重复值(例如通过重新创建元组)的解决方案,因为这可能会导致拼写错误并使 add/remove 稍后的属性。
首先您需要将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 中,您可以访问 valid 值(Int
、String
、String
)并且您可以创建有效对象。
toValidatedNel()
在这里从 Validated<String, String>
转换为 Validated<Nel<String>, String>
,其中 Nel
是一个不能为空的列表。将错误累积为 List
很常见,因此它是内置的。
有关更多信息,您可以查看文档中的 Error Handling tutorial。
我有 class A
:
class A (private var z: String, private var y: String, private var x: Int)
我想为它创建一个故障保护生成器。构建器应该 return 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
或类似方法)并避免重复值(例如通过重新创建元组)的解决方案,因为这可能会导致拼写错误并使 add/remove 稍后的属性。
首先您需要将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 中,您可以访问 valid 值(Int
、String
、String
)并且您可以创建有效对象。
toValidatedNel()
在这里从 Validated<String, String>
转换为 Validated<Nel<String>, String>
,其中 Nel
是一个不能为空的列表。将错误累积为 List
很常见,因此它是内置的。
有关更多信息,您可以查看文档中的 Error Handling tutorial。