【问题标题】:How to simplify this code, which uses Option.fold in Scala?如何简化在 Scala 中使用 Option.fold 的代码?
【发布时间】:2014-06-30 12:22:47
【问题描述】:

假设我有以下功能

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

【问题讨论】:

  • str = g(str) 应该是 str => g(str) 吗?
  • @DonRoby 是的,我正在修复代码。
  • x.fold(default)(x => f(x)) == x.fold(default)(f) 让它变得更好
  • @sschaef 感谢您的更正。你是对的。

标签: scala option fold


【解决方案1】:

通过map的简单用法:

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

【讨论】:

  • 这里的“defaultFoo”在哪里?
  • @Michael ops,是的,然后没那么漂亮
  • 我建议去foldmap/getOrElse。在它们之间进行选择似乎主要是一个品味问题。但是为什么要同时使用呢?
【解决方案2】:

为了整理其他人所说的,第一个重大改进是让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")

【讨论】:

    猜你喜欢
    • 2022-01-24
    • 2021-05-07
    • 2021-08-03
    • 2017-12-19
    • 2022-06-20
    • 2019-08-20
    • 1970-01-01
    • 1970-01-01
    • 2018-04-17
    相关资源
    最近更新 更多