gpt4 book ai didi

scala - 在 Scala 中避免深度嵌套的 Option 级联

转载 作者:行者123 更新时间:2023-12-04 06:59:48 24 4
gpt4 key购买 nike

假设我有三个数据库访问函数 foo , bar , 和 baz可以各自返回Option[A]哪里A是一些模型类,调用相互依赖。

我想按顺序调用这些函数,并且在每种情况下,如果找不到值( None ),则返回适当的错误消息。

我当前的代码如下所示:

Input is a URL: /x/:xID/y/:yID/z/:zID

foo(xID) match {
case None => Left(s"$xID is not a valid id")
case Some(x) =>
bar(yID) match {
case None => Left(s"$yID is not a valid id")
case Some(y) =>
baz(zID) match {
case None => Left(s"$zID is not a valid id")
case Some(z) => Right(process(x, y, z))
}
}
}

可以看出,代码嵌套严重。

如果相反,我使用 for理解,我不能给出具体的错误信息,因为我不知道哪一步失败了:
(for {
x <- foo(xID)
y <- bar(yID)
z <- baz(zID)
} yield {
Right(process(x, y, z))
}).getOrElse(Left("One of the IDs was invalid, but we do not know which one"))

如果我使用 mapgetOrElse ,我最终得到的代码几乎与第一个示例一样嵌套。

这些是否有更好的方法来构建它以避免嵌套,同时允许特定的错误消息?

最佳答案

您可以获取您的 for通过使用正确的投影循环工作。

def ckErr[A](id: String, f: String => Option[A]) = (f(id) match {
case None => Left(s"$id is not a valid id")
case Some(a) => Right(a)
}).right

for {
x <- ckErr(xID, foo)
y <- ckErr(yID, bar)
z <- ckErr(zID, baz)
} yield process(x,y,z)

这仍然有点笨拙,但它具有成为标准库的一部分的优势。

异常是另一种方法,但如果失败案例很常见,它们会大大减慢速度。如果失败真的很特别,我只会使用它。

也可以使用非本地返回,但对于这种特定设置来说有点尴尬。我认为 Either 的正确预测是要走的路。如果您真的喜欢这种方式工作但不喜欢放置 .right到处都是,你可以在很多地方找到一个“偏右的任一个”,默认情况下它会像正确的投影一样(例如 ScalaUtils ,Scalaz 等)。

关于scala - 在 Scala 中避免深度嵌套的 Option 级联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28884742/

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