什么';在Scala中执行map/getOrElse返回单元的惯用方法是什么?

什么';在Scala中执行map/getOrElse返回单元的惯用方法是什么?,scala,functional-programming,Scala,Functional Programming,如果一个值是某个(…)的话,最惯用的方法是做副作用,如果一个值是无的话,做另一个副作用。以下是我目前倾向于写的内容: def doSideEffectA(value: Int) { // ... } def doSideEffectB() { // ... } def doSideEffect(valueOption: Option[Int]) { valueOption map { value => doSideEffectA(value) } getOrEl

如果一个值是某个(…)的话,最惯用的方法是做副作用,如果一个值是无的话,做另一个副作用。以下是我目前倾向于写的内容:

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映射{…}getOrElse{…}返回的单元不太满意,因为我并没有从我的选项[Int]中真正“得到”任何东西。

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

valueOption match {
  case Some(value) => doSideEffectA(value)
  case None => doSideEffectB()
}
最惯用的方法实际上是模式匹配。否则,您可以创建一个隐式包装器,该包装器提供所需的方法:

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的答案中的一个更好地匹配所需的用法。

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

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

使用scalaz,您可以在
选项
上获得一个
折叠
方法,该方法接受两个函数并执行其中一个,具体取决于您是否有
部分

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

scala> none[String].fold({ x => println(x) }, println("FOO"))
FOO
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)
  }

Scala 2.10在
选项
上包含一个
折叠
方法,适用于需要
部分
解析为相同类型(包括
单元
)的任何情况:


模式匹配有什么问题?没什么。除此之外,对于布尔模式,它有点冗长。使用Option,我直觉上倾向于使用map/getOrElse和foreach。我想我想写一些类似的东西:valueOption foreach{…}或othis{…},来扩展现有的foreach模式。scala 2.10已经。我认为这最终将是最惯用的方式。这可能是做我想做的事情最惯用的方式,至少在scala 2.9中,但是它感觉有点像使用模式匹配(值匹配{case true=>…;case false=>…;})而不是if(值){…}else{…}。@OlivierBruchez您可以使用
if(值){…}else{…}
if
dosideeffect
不需要从
Some
中提取任何内容。这就是模式匹配和简单条件之间的区别;它既检查模式是否匹配,又提取一些数据。
scala> Option("salmon").fold(println("No fish")){f => println(s"I like $f")}
I like salmon