简体   繁体   English

在Scala中执行map / getOrElse返回单位的惯用方式是什么?

[英]What's the idiomatic way to do a map/getOrElse returning Unit in Scala?

What's the most idiomatic way to do a side-effect if a value is Some(...) and do another side-effect if a value is None. 如果值为Some(...),则最常见的副作用方式是:如果值为None,则另作另一种副作用。 Here's what I'd currently tend to write: 这是我目前倾向于写的内容:

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

def doSideEffectB() {
  // ...
}

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

My problem is that if I didn't have to do anything if valueOption is None, here's what I'd write: 我的问题是,如果valueOption为None时我不必执行任何操作,那么我将编写以下内容:

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

map/getOrElse are usually not used in a side-effect context, while foreach is. map / getOrElse通常不在副作用上下文中使用,而foreach则使用。 I'm not really comfortable with valueOption map { ... } getOrElse { ... } returning Unit, as I don't really "get" anything from my Option[Int]. 我对valueOption map {...} getOrElse {...}返回Unit并不太满意,因为我实际上从我的Option [Int]中没有“得到”任何东西。

What Kim Stebel said: pattern matching is a simple solution. Kim Stebel所说的:模式匹配是一个简单的解决方案。

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

Scala 2.10 includes a fold method on Option which is suitable for any case where you need both None and Some to resolve to the same type (including Unit ): Scala 2.10在Option上包含一个fold方法,适用于需要NoneSome都解析为相同类型(包括Unit )的任何情况:

scala> Option("salmon").fold(println("No fish")){f => println(s"I like $f")}
I like salmon

With scalaz you get a fold method on Option , that takes two functions and executes one of them depending on whether you have a Some or a None : 使用scalaz,您可以在Option上获得fold方法,该方法需要两个函数并根据您是否具有SomeNone执行其中之一:

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

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

Scalaz has cata , which would allow you to state it like this: Scalaz具有cata ,可以让您这样声明:

valueOption.cata(doSideEffectA, doSideEffectB)

Never used it, but it looks pretty useful and readable to me. 从未使用过它,但是对我来说,它看起来非常有用且可读。 This is how it's implemented: 这是它的实现方式:

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

Despite the fact that I still think pattern matching is the most readable option, you can also have it your way and define a wrapper around Option with an implicit conversion. 尽管我仍然认为模式匹配是最易读的选项,但您也可以按照自己的方式进行操作,并使用隐式转换围绕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)

Then you can write for example: 然后,您可以编写例如:

Some(1) each println orDoThis println("nothing there")

The most idiomatic way really is pattern matching. 惯用的方式实际上是模式匹配。 Otherwise, you can create an implicit wrapper which provides the desired method: 否则,您可以创建一个提供所需方法的隐式包装器:

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

EDIT: the one in @KimStebel's answer better matches the desired usage. 编辑:@KimStebel的答案中的一个更好地匹配了所需的用法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM