Option.fold()()和Option.map()。getOrElse()有什么区别?

Ada*_*ler 5 scala

Option类有一个名为方法fold()。文档说:

sealed abstract class Option[+A] 

fold[B](ifEmpty: ? B)(f: (A) ? B): B
Run Code Online (Sandbox Code Playgroud)

如果scala.Option为非空,则返回将f应用于此scala.Option的值的结果。否则,计算表达式ifEmpty

该文档继续:

这等效于scala.Option映射f getOrElse ifEmpty

但这是真的吗?有人告诉我,在某些情况下,某些类型的值存在差异,但从来没有一个体面的解释。这两种构造在不同情况下的确切情况是什么?为什么?

pra*_*upd 6

Option.fold比更加安全.getOrElse。您可以在.fold下面看到其中ifEmptyf均为类型的定义B(可能仅在scala 2.10之后引入)

  @inline final def fold[B](ifEmpty: => B)(f: A => B): B =
    if (isEmpty) ifEmpty else f(this.get)
Run Code Online (Sandbox Code Playgroud)

这意味着您可能不会弄乱数据类型(以下例外),

scala> val data = Option("massive data").fold(-1) { _ => 1 }
data: Int = 1

// but if i try to return different type in either of ifEmpty or f
// compiler will curse me right at my face   
scala> val data = Option("massive data").fold(-1) { _ => "Let me caught by compiler" }
<console>:17: error: type mismatch;
 found   : String("Let me caught by compiler")
 required: Int
       val data = Option("massive data").fold(-1) { _ => "Let me caught by compiler" }
                                                     ^
Run Code Online (Sandbox Code Playgroud)

getOrElse除非手动提供类型(以下定义中的超类型)B否则While 并不安全。

  @inline final def getOrElse[B >: A](default: => B): B =
    if (isEmpty) default else this.get
Run Code Online (Sandbox Code Playgroud)

这意味着您可以返回的类型getOrElse与原始值所返回的类型不同Option[A]

scala> val data = Option("massive data").map(_ => 1).getOrElse(List("I'm not integer"))
data: Any = 1

//you have to manually mention the type to getOrElse to restrict, 
// which is not that smart in my opinion
scala> val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
<console>:17: error: type mismatch;
 found   : List[String]
 required: Int
       val data = Option("massive data").map(_ => 1).getOrElse[Int](List("I'm not integer"))
                                                                    ^
Run Code Online (Sandbox Code Playgroud)

有趣的是,你可以返回unitgetOrElsefold除非你在单位的口味赶上它可以在应用程序引入错误。

scala> val data = Option("massive data").fold() { _ => 1 }
data: Unit = ()

scala> val data = Option("massive data").map(_ => 1).getOrElse()
data: AnyVal = 1
Run Code Online (Sandbox Code Playgroud)


Ale*_*nov 5

作为与 @prayagupd 答案的对立面,fold它经常邀请您以特定的方式搞乱类型。

问题在于,根据 Scala 的规则,仅ifEmpty用于推断 B,然后f检查是否合适。这意味着使用NoneNilas ifEmpty,这是很常见的,将导致它们的单例类型被用作而B不是Option/List[SomeType],无论f返回什么。

当然,有一些解决方法:B显式指定、使用Option.empty[SomeType]orNone: Option[SomeType]代替None. 或者只是使用模式匹配。