为什么Scala无法在通用函数类型参数推断中将Null类型识别为T的子类型?

时间:2016-06-05 01:26:06

标签: scala generics scala-generics

我在scala中有以下函数定义:

trait GenExtractor[+R] P
      def orElseExtractor[R2<: Super, Super>: R](g: GenExtractor[T, R2]): GenExtractor[T, Super] =
        new OrElse[T, Super](this, g)
}

应该结合2个GenExtractors:

GenExtractor[A]
GenExtractor[B]

成:

GenExtractor[C]

其中C是A和B的常见超类型

但是,当我尝试调用此函数时:

val genExtractor = new GenExtractor[R](...parameters...)
val combined = genExtractor.orElseExtractor[Null, R] {
      _: FetchedRow => null
    }

我收到以下错误:

Error:(84, 47) type arguments [Null,R] do not conform to method orElseExtractor's type parameter bounds [R2 <: Super,Super >: R]
    def orNull: Extractor[R] = orElseExtractor[Null, R] {
                                              ^

在这种情况下,这显然是一种误报:

type R2 = Null
type Super = R

满足条件:Null&lt;:R&amp; R&gt;:R

为什么scala编译器给了我这个错误?我该怎么做才能解决它?

1 个答案:

答案 0 :(得分:3)

为什么Null会成为通用R的子类型?它不是编译器的标记,它是Null <: R始终为真的基本假设。这里有一些有趣的例子,它们与原语有关。

Some(5).orNull将产生error: Cannot prove that Null <:< Int

这是你的差距,你可以在REPL中试一试:

implicitly[Null <:< AnyRef] // will compile
implicitly[Null <:< AnyVal] // blows up, primitives are not included.

在类型系统中,所有类型的超类型,唯一保证满足您期望的任何此类关系的类型,是scala.Nothing,而不是scala.Null

JVM上的

null主要用于处理缺少类型信息,而不是处理类型系统层次结构。为此,您有NothingAnyRefAnyVal以及所有其他有趣的内容。