关于 Scala 的解释以理解 Option
explanation on scala for comprehension with Option
我有以下定义:
def f: Option[String] = Some(null)
以下计算结果为 None:
for {x:String <- f} yield {
x
}
以下计算结果为 Some(null):
for {x <- f} yield {
x
}
以下计算结果为 Some(null):
f.map((x:String) => x)
我想知道为什么它们之间存在差异?
嗯...我要说的第一件事是"When in Scala-land, stay as far as possible from a null-monster"。他们很危险。
现在...要理解这种行为,您需要在 Scala 中尝试的第一件事-shell 如下,
scala> val n = null
n: Null = null
所以...在 Scala 中 null
是这个 class 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
时表现得更 "intelligently" 并在您尝试包装 null
.
时给您 None
现在...让我们先看看 map
是如何为 Option
,
实现的
final def map[B](f: A => B): Option[B] =
if (isEmpty) None else Some(f(this.get))
现在... "why Some(null).map((x: String) => x)
gives you Some(null)
?".
应该清楚了
至于理解 for
案例...这需要稍微了解 for
是如何使用 Repr
为 Option
实现的秒。而且行为会变得清晰。
脱糖发生在解析器中,因此 -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) => check$ifrefutable: @scala.unchecked match {
case (s @ (_: String)) => true
case _ => false
})).map(((s: String) => s))
}
}
}
}
res0: Option[String] = None
这让我感到惊讶,因为我认为以这种方式进行过滤是人们想要但未实现的功能。
类型模式只是一个 instanceof 测试,因此 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
^
我有以下定义:
def f: Option[String] = Some(null)
以下计算结果为 None:
for {x:String <- f} yield {
x
}
以下计算结果为 Some(null):
for {x <- f} yield {
x
}
以下计算结果为 Some(null):
f.map((x:String) => x)
我想知道为什么它们之间存在差异?
嗯...我要说的第一件事是"When in Scala-land, stay as far as possible from a null-monster"。他们很危险。
现在...要理解这种行为,您需要在 Scala 中尝试的第一件事-shell 如下,
scala> val n = null
n: Null = null
所以...在 Scala 中 null
是这个 class 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
时表现得更 "intelligently" 并在您尝试包装 null
.
None
现在...让我们先看看 map
是如何为 Option
,
final def map[B](f: A => B): Option[B] =
if (isEmpty) None else Some(f(this.get))
现在... "why Some(null).map((x: String) => x)
gives you Some(null)
?".
至于理解 for
案例...这需要稍微了解 for
是如何使用 Repr
为 Option
实现的秒。而且行为会变得清晰。
脱糖发生在解析器中,因此 -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) => check$ifrefutable: @scala.unchecked match {
case (s @ (_: String)) => true
case _ => false
})).map(((s: String) => s))
}
}
}
}
res0: Option[String] = None
这让我感到惊讶,因为我认为以这种方式进行过滤是人们想要但未实现的功能。
类型模式只是一个 instanceof 测试,因此 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
^