7

我试图理解在 for-comprehension 中处理 null 和类型注释时看起来很奇怪的行为。

举个例子:

def f(): String = null

for {
  a <- Option("hello")
  b = f()
} yield (a, b)

结果是预期的:

//> res0: Option[(String, String)] = Some((hello,null)) 

但是,如果我将类型注释添加到b

def f(): String = null

for {
  a <- Option("hello")
  b: String = f()
} yield (a, b)

然后我得到一个运行时异常:

//> scala.MatchError: (hello,null) (of class scala.Tuple2)

为什么会这样?无论如何,第一个示例中的类型不是b隐含的吗?String第二个示例中的显式类型注释有什么变化?

(注意,示例在 Scala 2.11.4 中运行)

4

1 回答 1

7

null不是任何事物的实例:

scala> (null: String) match { case _: String => }
scala.MatchError: null
  ... 33 elided

scala> val s: String = null
s: String = null

scala> s.isInstanceOf[String]
res1: Boolean = false

http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#type-patterns

类型模式指定非空。

显示翻译的一个技巧是评论显示:

scala> for {
     |   a <- Option("hello")
     |   b: String = f()
     | } yield (a, b) // show
object $read extends scala.AnyRef {
  def <init>() = {
    super.<init>;
    ()
  };
  object $iw extends scala.AnyRef {
    def <init>() = {
      super.<init>;
      ()
    };
    import $line4.$read.$iw.$iw.f;
    object $iw extends scala.AnyRef {
      def <init>() = {
        super.<init>;
        ()
      };
      val res1 = Option("hello").map(((a) => {
        val b: String = f;
        scala.Tuple2(a, b)
      })).map(((x$1) => x$1: @scala.unchecked match {
        case scala.Tuple2((a @ _), (b @ (_: String))) => scala.Tuple2(a, b)
      }))
    }
  }
}
scala.MatchError: (hello,null) (of class scala.Tuple2)
  at $anonfun$2.apply(<console>:10)
  at $anonfun$2.apply(<console>:10)
  at scala.Option.map(Option.scala:145)
  ... 39 elided
于 2015-01-06T00:31:10.073 回答