我有以下定义:
def f: Option[String] = Some(null)
以下评估为无:
for {x:String <- f} yield {
x
}
以下评估为Some(null):
for {x <- f} yield {
x
}
以下评估为Some(null):
f.map((x:String) => x)
我想知道为什么它们之间存在差异?
答案 0 :(得分:5)
在解析器中发生了desugaring,因此-Xprint:parser
显示了差异:
$ scala -Xprint:parser
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> for (s: String <- (Some(null): Option[String])) yield s
[[syntax trees at end of parser]] // <console>
package $line3 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res0 = (Some(null): Option[String]).withFilter(((check$ifrefutable$1) => check$ifrefutable$1: @scala.unchecked match {
case (s @ (_: String)) => true
case _ => false
})).map(((s: String) => s))
}
}
}
}
res0: Option[String] = None
这让我感到惊讶,因为我认为以这种方式过滤是人们想要但未实现的功能。
类型模式只是一个测试实例,因此null无法通过该测试。
没有过滤器:
scala> for (s <- (Some(null): Option[String])) yield s
[[syntax trees at end of parser]] // <console>
package $line4 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res1 = (Some(null): Option[String]).map(((s) => s))
}
}
}
}
res1: Option[String] = Some(null)
在2.9:
$ scala29
Welcome to Scala version 2.9.3 (OpenJDK 64-Bit Server VM, Java 1.6.0_38).
Type in expressions to have them evaluated.
Type :help for more information.
scala> for (s: String <- (Some(null): Option[String])) yield s
res0: Option[String] = Some(null)
所以在2.10.x中添加了过滤功能。
编辑:实际上,this是你没有得到的:
scala> for (s: String <- (Some("x"): Option[Any])) yield s
<console>:12: error: type mismatch;
found : String => String
required: Any => ?
for (s: String <- (Some("x"): Option[Any])) yield s
^
答案 1 :(得分:1)
嗯......我要说的第一件事是&#34;当在Scala-land时,尽可能远离零怪物&#34;。它们很危险。
现在......为了理解这种行为,你需要在Scala-shell中尝试的第一件事是,
scala> val n = null
n: Null = null
所以...在Scala中null
是此类Null
的实例。
现在......让我们看看当我们将null
与Option
,
scala> val nullOpt1 = Option(null)
nullOpt1: Option[Null] = None
scala> val nullOpt2 = Some(null)
nullOpt2: Some[Null] = Some(null)
注意两者之间的区别...所以基本上Scala人认为可能有人想要将null
包裹到Option
...所以他们允许他们explicitly
使用Some.apply
将null
打包成Option
。使用Option.apply
表现更多&#34;智能&#34;并在尝试换行None
时为您提供null
。
现在......让我们先来看看map
Option
是如何实现的
final def map[B](f: A => B): Option[B] =
if (isEmpty) None else Some(f(this.get))
现在......应该明白为什么Some(null).map((x: String) => x)
会给你Some(null)
?&#34;。
至于了解for
个案例......需要了解for
如何Option
使用Repr
&#39 ; S。行为将变得清晰。