8

如果一个值是 Some(...) 并且如果一个值是 None 做另一个副作用,那么最惯用的方法是什么。以下是我目前倾向于写的内容:

def doSideEffectA(value: Int) {
  // ...
}

def doSideEffectB() {
  // ...
}

def doSideEffect(valueOption: Option[Int]) {
  valueOption map { value =>
    doSideEffectA(value)
  } getOrElse {
    doSideEffectB()
  }
}

我的问题是,如果 valueOption 为 None,我不需要做任何事情,这就是我要写的:

def doSideEffectNothingIfNone(valueOption: Option[Int]) {
  valueOption foreach { value =>
    doSideEffectA(value)
  }
}

map/getOrElse 通常不用于副作用上下文,而 foreach 是。我对 valueOption map { ... } getOrElse { ... } 返回 Unit 不太满意,因为我并没有真正从我的 Option[Int] 中“获取”任何东西。

4

6 回答 6

13

Kim Stebel 说的:模式匹配是一个简单的解决方案。

valueOption match {
  case Some(value) => doSideEffectA(value)
  case None => doSideEffectB()
}
于 2012-11-07T10:51:29.653 回答
9

Scala 2.10 包含一个fold方法Option,适用于您需要两者NoneSome解析为相同类型(包括Unit)的任何情况:

scala> Option("salmon").fold(println("No fish")){f => println(s"I like $f")}
I like salmon
于 2012-11-07T14:11:41.470 回答
4

使用 scalaz 你会得到一个fold方法 on Option,它接受两个函数并根据你是 aSome还是 a来执行其中一个函数None

scala> some(3).fold({ x => println(x) }, println("FOO"))
3

scala> none[String].fold({ x => println(x) }, println("FOO"))
FOO
于 2012-11-07T11:13:14.870 回答
4

Scalaz has cata,这将允许您像这样声明它:

valueOption.cata(doSideEffectA, doSideEffectB)

从未使用过它,但对我来说它看起来非常有用且可读。这是它的实现方式:

  /**
   * Catamorphism over the option. Returns the provided function `some` applied to item contained in the Option
   * if it is defined, otherwise, the provided value `none`.
   */
  def cata[X](some: A => X, none: => X): X = value match {
    case None => none
    case Some(a) => some(a)
  }
于 2012-11-07T11:37:35.717 回答
3

尽管我仍然认为模式匹配是最易读的选项,但您也可以按照自己的方式使用它,并Option使用隐式转换定义一个包装器。

class Else(doit:Boolean) {
  def orDoThis[A](f: =>A) {
    if (doit) f
  }
}

class OptionWrapper[A](o:Option[A]) {
  def each[B](f: A=>B):Else = o match {
    case Some(v) => f(v); new Else(false)
    case None => new Else(true)
  }
}

implicit def wrapOption[A](o:Option[A]):OptionWrapper[A] = new OptionWrapper(o)

然后你可以写例如:

Some(1) each println orDoThis println("nothing there")
于 2012-11-07T11:11:41.863 回答
1

最惯用方式确实是模式匹配。否则,您可以创建一个提供所需方法的隐式包装器:

class RichOption[T](o: Option[T]) {
  def ifEmpty(action: => Unit) { if (o.isEmpty) action }
}

object RichOption {
  implicit def enrich(o: Option[T]) = return new RichOption(o)
}

编辑:@KimStebel 的答案中的那个更符合所需的用法。

于 2012-11-07T11:02:22.657 回答