标识符、名称和作用域
Scala 中的名称标识类型、值、方法和类,这些统称为实体。名称由局部定义、继承、导入语句或包语句引入,这些统称为绑定。
不同类型的绑定具有定义的优先级。
- 在与引用它们的编译单元相同的编译单元中定义的局部、继承或由包语句提供的定义具有最高优先级。
- 显式导入具有次高优先级。
- 通配符导入具有次次高优先级。
- 由包语句提供的定义,但不在与引用它们的编译单元相同的编译单元中定义,以及由编译器提供但未在源代码中显式编写的导入,具有最低优先级。
存在两个不同的命名空间,一个用于类型,另一个用于项。同一个名称可能表示类型和项,具体取决于使用该名称的上下文。
绑定具有作用域,在该作用域中,可以使用简单名称访问由单个名称定义的实体。作用域是嵌套的。某个内部作用域中的绑定会遮蔽同一作用域中优先级较低的绑定,以及外部作用域中优先级相同或较低的绑定。
请注意,遮蔽只是偏序关系。在以下示例中,x
的两个绑定都不会遮蔽对方。因此,块中最后一行对 x
的引用是模棱两可的。
对未限定的(类型或项)标识符 ´x´ 的引用由唯一的绑定绑定,该绑定
- 在与标识符相同的命名空间中定义一个名为“x”的实体,并且
- 会覆盖该命名空间中所有其他定义名为“x”的实体的绑定。
如果不存在这样的绑定,则会发生错误。如果“x”由导入子句绑定,则简单名称“x”被视为等同于导入子句将“x”映射到的限定名称。如果“x”由定义绑定,则“x”引用由该绑定引入的实体。在这种情况下,“x”的类型是引用实体的类型。
对限定(类型或术语)标识符“e.x”的引用是指类型“T”的成员,该成员是“e”的成员,并且在与标识符相同的命名空间中具有名称“x”。如果“T”不是值类型,则会发生错误。“e.x”的类型指定为类型指示符。
绑定优先级意味着源代码在文件中的捆绑方式会影响名称解析。特别是,导入的名称优先级高于其他文件中定义的名称,这些名称可能因为在当前包或封闭包中定义而可见。
请注意,包定义的优先级最低,因为包是开放的,可以在任意编译单元中定义。
编译器在每个源文件的序言中提供导入。从概念上讲,此序言具有以下形式,其中大括号表示嵌套范围
这些导入的优先级最低,因此它们始终会被用户代码覆盖,用户代码可能包含竞争的导入和定义。它们还会增加嵌套深度,如所示,因此后面的导入会覆盖前面的导入。
为了方便起见,允许将类型标识符的多个绑定绑定到相同的底层类型。当导入子句引入具有相同绑定优先级的成员类型别名的绑定时,这通常通过通配符导入实现。这允许导入冗余类型别名,而不会引入歧义。
类似地,允许导入由包语句引入的名称的别名,即使这些名称严格来说是模棱两可的
对X
定义中的C
的引用严格来说是模棱两可的,因为C
可以通过不同文件中的包子句获得,并且不能覆盖导入的名称。但由于引用相同,因此该定义被视为覆盖了导入。
示例
假设在不同的编译单元中,包p
和q
中分别定义了名为X
的两个对象。
以下程序说明了不同类型的绑定及其之间的优先级。