Crates 和源文件
语法
箱 :
内部属性(InnerAttribute)*
项(Item)*
注意
虽然 Rust 和任何其他语言一样,既可以由解释器实现,也可以由编译器实现,但目前唯一的实现是编译器,并且该语言一直以来都设计用于编译。因此,本节假设使用编译器。
Rust 的语义遵循编译时(compile-time)和运行时(run-time)之间的阶段区分(phase distinction)。1 具有静态解释(static interpretation)的语义规则决定编译的成功或失败,而具有动态解释(dynamic interpretation)的语义规则决定程序在运行时(run-time)的行为。
编译模型围绕着称为箱(crate)的工件展开。每次编译都处理一个源形式的箱,如果成功,则生成一个二进制形式的箱:要么是可执行文件,要么是某种库。2
一个箱(crate)是编译和链接的单元,也是版本控制、分发和运行时加载的单元。一个箱包含一个嵌套的模块(module)作用域树(tree)。这棵树的顶层是一个匿名模块(从模块内部路径的角度来看),箱内的任何项都有一个规范的模块路径(module path),表示它在该箱的模块树中的位置。
Rust 编译器总是以单个源文件作为输入调用,并且总是生成单个输出箱(crate)。对该源文件的处理可能导致其他源文件被加载为模块。源文件使用扩展名 .rs
。
一个 Rust 源文件描述了一个模块,其名称和位置——在当前箱的模块树中——由源文件外部定义:要么是通过引用源文件中的显式 Module 项,要么是通过箱本身的名称。
每个源文件都是一个模块,但并非每个模块都需要自己的源文件:模块定义可以嵌套在一个文件中。
每个源文件包含零个或多个 项(Item) 定义序列,并且可以选择性地以适用于所在模块的任意数量的 属性(attribute) 开头,其中大部分属性会影响编译器的行为。
匿名箱模块可以有适用于整个箱的额外属性。
注意
文件的内容可能前面有一个 shebang。
#![allow(unused)] fn main() { // Specify the crate name. #![crate_name = "projx"] // Specify the type of output artifact. #![crate_type = "lib"] // Turn on a warning. // This can be done in any module, not just the anonymous crate module. #![warn(non_camel_case_types)] }
主函数
包含 main
函数的箱可以被编译为可执行文件。
如果存在 main
函数,它必须不接受任何参数,不能声明任何 trait 或生命周期约束(trait or lifetime bounds),不能有任何 where 子句(where clauses),并且其返回类型必须实现 Termination
trait。
fn main() {}
fn main() -> ! { std::process::exit(0); }
fn main() -> impl std::process::Termination { std::process::ExitCode::SUCCESS }
main
函数可以是导入的,例如从外部箱或当前箱导入。
#![allow(unused)] fn main() { mod foo { pub fn bar() { println!("Hello, world!"); } } use foo::bar as main; }
注意
标准库中实现了
Termination
的类型包括
()
!
Infallible
ExitCode
Result<T, E>,其中 T: Termination, E: Debug
未捕获的外部展开
当一个“外部”展开(例如从 C++ 代码抛出的异常,或使用不同 panic handler 的 Rust 代码中的 panic!
)传播到 main
函数之外时,进程将安全终止。这可能表现为中止(abort),在这种情况下,不保证会执行任何 Drop
调用,并且错误输出可能不如由“原生” Rust panic
终止运行时那样提供更多信息。
更多信息,请参阅panic 文档。
no_main
属性
no_main
属性可以应用于箱级别,以禁用为可执行二进制文件发出 main
符号。当链接到的其他对象定义了 main
时,这很有用。
crate_name
属性
crate_name
属性可以应用于箱级别,使用 MetaNameValueStr 语法指定箱的名称。
#![allow(unused)] #![crate_name = "mycrate"] fn main() { }
箱名称不能为空,且只能包含 Unicode 字母数字或 _
(U+005F) 字符。
这种区别在解释器中也存在。静态检查如语法分析、类型检查和 lint 无论何时执行程序,都应该在程序执行之前发生。
箱在某些方面类似于 ECMA-335 CLI 模型中的 assembly,SML/NJ 编译管理器中的 library,Owens 和 Flatt 模块系统中的 unit,或者 Mesa 中的 configuration。