gpt4 book ai didi

scala - 通过任一/析取 Scala 处理多种错误类型

转载 作者:行者123 更新时间:2023-12-01 23:36:02 25 4
gpt4 key购买 nike

我有 3 个不同的模块,每个模块都有自己的错误类型。以下是一个非常简化的版本。

object ModuleA {
case class ErrorA(msg: String)
def getA: ErrorA \/ String = "1".right
}

object ModuleB {
case class ErrorB(msg: String)
def getB(s: String): ErrorB \/ Int = 1.right
}

object ModuleC {
case class ErrorC(msg: String)
def getC(s: String, i: Int): ErrorC \/ Long = 1L.right
}

作为这些模块的客户,链接这些调用的最佳方式是什么。

首先 - 深度嵌套的复杂返回类型,但具有所需的所有类型。
def call1: ModuleA.ErrorA \/ (ModuleB.ErrorB \/ (ModuleC.ErrorC \/ Long)) = {
ModuleA.getA.map { s =>
ModuleB.getB(s).map { i =>
ModuleC.getC(s, i)
}
}
}

第二 - 非常易读,但错误类型丢失(推断返回类型为 Product \/ Long )。理想情况下,需要与错误类型类似的东西
def call2  =
for {
s <- ModuleA.getA
i <- ModuleB.getB(s)
l <- ModuleC.getC(s, i)
} yield l

第三 - 定义新的错误类型来封装现有的。这对于不同的组合似乎是不可行的

最后,尝试使用 EitherT,但似乎变得复杂

最佳答案

考虑从错误中创建代数数据类型,用于 example

sealed abstract class Error(val message: String)
case class ErrorA(msg: String) extends Error(msg)
case class ErrorB(msg: String) extends Error(msg)
case class ErrorC(msg: String) extends Error(msg)

然后更改返回的 \/的左侧至 Error
import scalaz.\/
import scalaz.syntax.either._

object ModuleA {
def getA: Error \/ String = "1".right
}

object ModuleB {
def getB(s: String): Error \/ Int = ErrorB("boom").left
}

object ModuleC {
def getC(s: String, i: Int): Error \/ Long = 1L.right
}

for {
s <- ModuleA.getA
i <- ModuleB.getB(s)
l <- ModuleC.getC(s, i)
} yield l

这使
res0: Error \/ Long = -\/(ErrorB(boom))

如果您无法创建 ADT,请考虑 leftMap将错误类型更改为像这样的常见类型
case class ErrorWrapper(m: String)

for {
s <- ModuleA.getA.leftMap { e: ModuleA.ErrorA => ErrorWrapper(e.msg) }
i <- ModuleB.getB(s).leftMap { e: ModuleB.ErrorB => ErrorWrapper(e.msg) }
l <- ModuleC.getC(s, i).leftMap { e: ModuleC.ErrorC => ErrorWrapper(e.msg) }
} yield l
// res0: ErrorWrapper \/ Long = -\/(ErrorWrapper(boom))

或者甚至,不寻常地,通过结构类型
implicit class CommonErrorWrapper[A <: Product { def msg: String }](e: A) {
def toErrorWrapper: ErrorWrapper = ErrorWrapper(e.msg)
}

for {
s <- ModuleA.getA.leftMap(_.toErrorWrapper)
i <- ModuleB.getB(s).leftMap(_.toErrorWrapper)
l <- ModuleC.getC(s, i).leftMap(_.toErrorWrapper)
} yield l
// res1: ErrorWrapper \/ Long = -\/(ErrorWrapper(boom))
leftMap不仅对于更改错误类型很有用,而且我们可以通过添加本地可用的上下文信息来丰富错误。

备注 EitherT当类型的形状为 F[A \/ B] 时,可以使用单子(monad)更改器(mutator)。 ,例如 Future[Error \/ B] ,但是在您的情况下,它只是 A \/ B ,因此 EitherT这可能不是正确的工具。相关问题 EitherT with multiple return types

关于scala - 通过任一/析取 Scala 处理多种错误类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60313644/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com