在Scala中执行map / getOrElse返回Unit的惯用方法是什么?

时间:2012-11-07 10:42:58

标签: scala functional-programming

如果值为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]中“获取”任何东西。

6 个答案:

答案 0 :(得分:13)

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

valueOption match {
  case Some(value) => doSideEffectA(value)
  case None => doSideEffectB()
}

答案 1 :(得分:9)

Scala 2.10在fold上包含Option方法,适用于您需要NoneSome同时解析为相同类型的任何情况(包括{{ 1}}):

Unit

答案 2 :(得分:4)

使用scalaz,您会在fold上获得Option方法,该方法需要两个函数并执行其中一个,具体取决于您是Some还是None:< / p>

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

scala> none[String].fold({ x => println(x) }, println("FOO"))
FOO

答案 3 :(得分:4)

Scalazcata,您可以这样说明:

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)
  }

答案 4 :(得分: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")

答案 5 :(得分: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答案中的答案更符合所需的用法。