例如:
abstract type
ClassSymbol >: Null <: Universe.TypeSymbol with Universe.ClassSymbolApi
找到here。我意识到这有什么描述,但从语法的角度来看,我无法理解它。
Null的目的是什么?看起来它可能是某种默认值,但我只是猜测,因为我只看到这种类型的语法,并且我认为null可以是类型的返回,而不会破坏程序。这是一个抽象类型,但它没有您稍后可以指定的参数,那么它如何作为抽象类型工作?
答案 0 :(得分:5)
Null
是一种指定某些内容可以null
的类型。严格来说,它不是超类型,因为你不能用null
做任何,除非传递它并检查它,是的,它仍然是null
。这样,它就像Nothing
一样,除了你甚至无法获得Nothing
的实例传递。
现在,有人可以说,“好吧,任何AnyRef
都可能是null
”,但那么您如何看待实例null
本身? null
可以填写几乎任何内容,作为一种类型,它意味着它必须是所有可以null
的子类型!这就是Null
的含义:所有可以Null
的子类型。
等等,你说。你不能实际拥有所有内容的子类型 - 这意味着null
将拥有所有可能的功能!如果您考虑一下,null
确实承诺任何AnyRef
所拥有的各种功能 - 但它们都是空的承诺,并且每当您尝试使用该功能时你会得到一个NullPointerException
。
现在,问题是,为什么要创建一个类型>: Null
(意味着null
是一个有效的值)而不是<: AnyRef
这应该意味着同样的事情?
嗯,事实证明,Scala实际上并没有这样做的方式,留下你可能拥有AnyRef
的可能性,你绝对不可能null
。{1}}。因此,要求<: AnyRef
(“我是AnyRef的子类”)在理论上并不意味着同样的事情,即使在实践中绝对不为空 - AnyRef
并未真正实现。 (另外,如果Any
不是显式类型,Null
会变得非常尴尬。)
所以type Foo >: Null <: Bar
只是意味着您明确承认null
可以填写任何可能类型Foo
的实例,因此您可以撰写val foo: Foo = null
。
答案 1 :(得分:3)
请考虑以下事项:
trait Foo {
type A >: Null
def someA: A = null
}
在上面的虚拟特征中,A
是一个带有类型绑定的抽象类型成员。这意味着:无论子类定义A
是什么,Null
必须是它的子类型。 (反之亦然:A <: Bar
)。
要做的主要原因是,使null
成为A
的有效值,如第二行所示。如果没有它,scalac会在第二行抱怨:
found : Null(null)
required: Foo.this.A
问题是Null
是什么:它是null
的类型,它是AnyRef
的子类型及其所有子类型。