加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在Scala中避免深层嵌套的选项级联

发布时间:2020-12-16 19:18:30 所属栏目:安全 来源:网络整理
导读:假设我有三个数据库访问函数foo,bar和baz,每个函数都可以返回Option [A],其中A是某个模型类,并且调用依赖于彼此. 我想按顺序调用这些函数,并且在每种情况下,如果找不到该值,则返回相应的错误消息(无). 我当前的代码如下所示: Input is a URL: /x/:xID/y/:yI
假设我有三个数据库访问函数foo,bar和baz,每个函数都可以返回Option [A],其中A是某个模型类,并且调用依赖于彼此.

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

我当前的代码如下所示:

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 comprehension,我不能给出具体的错误信息,因为我不知道哪一步失败了:

(for {
  x <- foo(xID)
  y <- bar(yID)
  z <- baz(zID)
} yield {
  Right(process(x,z))
}).getOrElse(Left("One of the IDs was invalid,but we do not know which one"))

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

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

解决方法

您可以使用正确的投影来使您的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,z)

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

例外是另一种方法,但如果失败的情况很常见,它们会使事情变得缓慢.如果失败真是异常,我只会用它.

也可以使用非本地回报,但这种特殊设置有点尴尬.我认为对Either的正确预测是要走的路.如果你真的喜欢以这种方式工作但是不喜欢把它放在那个地方,那么你可以在各个地方找到一个“右偏的Either”,它默认就像正确的投影(例如ScalaUtils,Scalaz等).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读