关于 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.

的一个实例

现在...让我们看看将此 nullOption

混合时会发生什么
scala> val nullOpt1 = Option(null)
nullOpt1: Option[Null] = None

scala> val nullOpt2 = Some(null)
nullOpt2: Some[Null] = Some(null)

注意两者之间的区别...所以基本上 Scala 的人认为可能有人想要将 null 包装成 Option... 所以他们允许他们 explicitly 使用 Some.applynull 包装成 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 是如何使用 ReprOption 实现的秒。而且行为会变得清晰。

脱糖发生在解析器中,因此 -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
                      ^