55-包的声明
包的介绍
当项目规模持续扩张,在单个超大文件里管理源代码,就如同在杂乱无章的巨大仓库找一件小物品,难度极大。此时,将源代码依
据功能进行分组,不同功能的代码分开管理是个很好的解决办法。每组独立管理的代码最终会生成一个输出文件。实际使用时,导
入对应的输出文件,就能调用相应功能,或者通过不同功能间的交互、组合,实现更复杂的特性,极大提升项目管理的效率。
在仓颉编程语言里,包堪称编译的最小单元。每个包都能单独输出AST文件、静态库文件、动态库文件等成果。每个包都有专属的
名字空间,在同一个包内,除了函数重载的情况,不允许出现同名的顶层定义或声明。一个包中还能容纳多个源文件。 模块则是若
干包的集合,它是第三方开发者发布的最小单元。
一个模块的程序入口位置限定在其根目录下,且顶层最多只能有一个用作程序入口的main
。这个main
要么没有参数,要么参数
类型为Array<String>
,返回类型为整数类型或者Unit
类型。
包的声明
在仓颉编程语言中,包声明以关键字 package
开头,后接 root 包至当前包由 .
分隔路径上所有包的包名。包名必须是合法的普通标识符(不含原始标识符)。例如:
package pkg1 // root 包 pkg1
package pkg1.sub1 // root 包 pkg1 的子包 sub1
包声明必须在源文件的非空非注释的首行,且同一个包中的不同源文件的包声明必须保持一致。
// file 1
// Comments are accepted
package test
// declarations...
// file 2
let a = 1 // Error, package declaration must appear first in a file
package test
// declarations...
仓颉的包名需反映当前源文件相对于项目源码根目录 src
的路径,并将其中的路径分隔符替换为小数点。例如包的源代码位于 src/directory_0/directory_1
下,root 包名为 pkg
则其源代码中的包声明应为 package pkg.directory_0.directory_1
。
需要注意的是:
- 包所在的文件夹名必须与包名一致。
- 源码根目录默认名为
src
。 - 源码根目录下的包可以没有包声明,此时编译器将默认为其指定包名
default
。
假设源代码目录结构如下:
// The directory structure is as follows:
src
`-- directory_0
|-- directory_1
| |-- a.cj
| `-- b.cj
`-- c.cj
`-- main.cj
则 a.cj
、b.cj
、c.cj
、main.cj
中的包声明可以为:
// a.cj
// in file a.cj, the declared package name must correspond to relative path directory_0/directory_1.
package default.directory_0.directory_1
// b.cj
// in file b.cj, the declared package name must correspond to relative path directory_0/directory_1.
package default.directory_0.directory_1
// c.cj
// in file c.cj, the declared package name must correspond to relative path directory_0.
package default.directory_0
// main.cj
// file main.cj is in the module root directory and may omit package declaration.
main() {
return 0
}
另外,包声明不能引起命名冲突:子包不能和当前包的顶层声明同名。
以下是一些错误示例:
// a.cj
package a
public class B { // Error, 'B' is conflicted with sub-package 'a.B'
public static func f() {}
}
// b.cj
package a.B
public func f {}
// main.cj
import a.B // ambiguous use of 'a.B'
main() {
a.B.f()
return 0
}