簡體   English   中英

在Scala中執行map / getOrElse返回單位的慣用方式是什么?

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

如果值為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]中沒有“得到”任何東西。

Kim Stebel所說的:模式匹配是一個簡單的解決方案。

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

Scala 2.10在Option上包含一個fold方法,適用於需要NoneSome都解析為相同類型(包括Unit )的任何情況:

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

使用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具有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)
  }

盡管我仍然認為模式匹配是最易讀的選項,但您也可以按照自己的方式進行操作,並使用隱式轉換圍繞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")

慣用的方式實際上是模式匹配。 否則,您可以創建一個提供所需方法的隱式包裝器:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM