顶级定义
编译单元
编译单元由一系列打包、导入语句以及类和对象定义组成,这些定义可能以一个包语句开头。
一个编译单元
以一个或多个包语句开头,等同于一个编译单元,该编译单元包含打包
每个编译单元都隐式导入以下包,按给定顺序
- 包
java.lang
, - 包
scala
,以及 - 对象
scala.Predef
,除非存在显式顶级导入引用scala.Predef
。
按此顺序,后面导入的成员会隐藏前面导入的成员。
对 scala.Predef
的隐式导入的例外情况可能很有用,例如,隐藏预定义的隐式转换。
打包
一个包是一个特殊的对象,它定义了一组成员类、对象和包。与其他对象不同,包不是由定义引入的。相反,包的成员集是由打包决定的。
打包 package ´p´ { ´\mathit{ds}´ }
将 ´\mathit{ds}´ 中的所有定义作为成员注入到限定名为 ´p´ 的包中。包的成员称为顶级定义。如果 ´\mathit{ds}´ 中的定义被标记为 private
,则它仅对包中的其他成员可见。
在打包内部,包 ´p´ 的所有成员在它们的简单名称下都是可见的。但是,此规则不扩展到 ´p´ 的封闭包的成员,这些成员由 ´p´ 路径的前缀指定。
包 org.net.prj
中的所有成员在其简单名称下可见,但包 org
或 org.net
中的成员需要显式限定或导入。
从 ´p´ 中选择 ´p´.´m´ 以及从 ´p´ 中导入,与对象的操作相同。但是,与其他对象不同,包不能用作值。具有与模块或类相同的完全限定名称的包是非法的。
包装之外的顶层定义被假定为注入到一个特殊的空包中。该包不能命名,因此不能导入。但是,空包的成员彼此可见,无需限定。
包对象
一个包对象 package object ´p´ extends ´t´
将模板 ´t´ 的成员添加到包 ´p´ 中。每个包只能有一个包对象。标准命名约定是在与包 ´p´ 相对应的目录中放置一个名为 package.scala
的文件,其中包含上述定义。
包对象不应定义与包 ´p´ 中定义的任何顶层对象或类同名的成员。如果存在名称冲突,程序的行为目前未定义。预计此限制将在 Scala 的未来版本中解除。
包引用
对包的引用采用限定标识符的形式。与所有其他引用一样,包引用是相对的。也就是说,从名称 ´p´ 开始的包引用将在定义名为 ´p´ 的成员的最近封闭范围内查找。
如果包名称被遮蔽,可以通过在它前面加上特殊的预定义名称 _root_
来引用它的完全限定名称,该名称引用包含所有顶层包的最外层根包。
名称 _root_
仅在用作限定符的第一个元素时具有此特殊含义;否则它是一个普通标识符。
示例
考虑以下程序
这里,引用 _root_.b.B
指的是顶层包 b
中的类 B
。如果省略了 _root_
前缀,名称 b
将解析为包 a.b
,并且,如果该包也不包含类 B
,则会产生编译时错误。
程序
一个程序是一个顶层对象,它拥有一个名为main的成员方法,类型为(Array[String])Unit
。程序可以从命令行执行。程序的命令参数作为类型为Array[String]
的参数传递给main
方法。
程序的main
方法可以直接在对象中定义,也可以被继承。Scala 库定义了一个特殊的类scala.App
,它的主体充当main
方法。因此,继承自该类的对象m
就是一个程序,它会执行对象m
的初始化代码。
示例
以下示例将通过在模块test.HelloWorld
中定义一个main
方法来创建一个“Hello World”程序。
这个程序可以通过以下命令启动
在 Java 环境中,以下命令
也可以正常工作。
HelloWorld
也可以通过继承App
而不是定义main
方法来定义