如何简化在Scala中使用Option.fold的代码?

时间:2014-06-30 12:22:47

标签: scala option fold

假设我有以下功能

def foo(x: Int): Option[String] = ...
def bar(s: String): Option[String] = ...

def f(s: String): String = ...
def g(s: String): String = ...

我想将所有这些功能组成如下:

def qux(x: Int): String = {
   val s1 = foo(x).fold("defaultFoo") { str => f(str) }
   bar(s1).fold("defaultBar") { str => g(str) }
}

在我看来,函数qux看起来不是特别优雅,我想知道如何简化它。你会怎么建议写qux

2 个答案:

答案 0 :(得分:2)

简单使用map

def quz(x: Int) = 
  bar(foo(x).fold("defaultFoo")(f))
    .map(g).getOrElse("defaultBar")

答案 1 :(得分:1)

为了编纂其他人所说的内容,第一个重大改进是让eta-expansion为你工作而不是手动制作闭包:

def qux(x: Int): String = {
  val s1 = foo(x).fold("defaultFoo")(f)
  bar(s1).fold("defaultBar")(g)
}

你也可以使用for...yield理解来推迟你的默认情况直到结束:

def qux(x: Int): String = {
   val result = for { s1 <- foo(x); s2 <- bar(f(s1)) } yield { g(s2) } 
   result.getOrElse("default result")
}

这里的问题是你失去了控制流中间的错误处理,因为更简单的组合器会通过None个案例。如果您需要保留相同的流程,可以尝试这样做:

def qux(x: Int): String = {
   val s1 = foo(x).map(f).getOrElse("defaultFoo") 
   bar(s1).map(g).getOrElse("defaultBar")
}

它并不比原始代码简单得多,但它有点简单,并且会将错误处理推送到每行的末尾。或者只是省略中间变量,并使其成为单行:

def qux(x: Int): String = bar(foo(x).map(f).getOrElse("defaultFoo")).map(g).getOrElse("defaultBar")