Crate和源码文件
词法
UTF8BOM :\uFEFF
执行注解 :#!
~\n
+†
注意:尽管 Rust 和其他语言相似,可以实现解释器,但目前仅实现了编译器,并且设计理念也是编译型语言。
Rust 的语义同样遵循 '编译时' 和 '运行时' 两个可区分阶段。 1 编译时的 静态解释 规则将决定编译的成功或失败,运行时的 动态解释 规则将决定程序运行的行为。
编译器进行编译的模型主要围绕 crate 。 每个编译过程处理独立的源码形式的 crate ,如果编译成功,将生成单个二进制 crate : 可执行文件或某种类型的库。2
译注: crate 概念不仅限于源码,编译后的文件也是 crate 的一部分。
crate 是编译、链接、版本控制、分发和运行时加载的基本单位。 crate 包含了一个嵌套的 模块 树 。 该树的最高层是一个匿名模块。 条目都有一个规范的 模块路径 以查找它在的模块树中的位置。
Rust 编译器总是使用单个源码文件作为输入,并输出产生单个 crate 。
在编译该源码文件时会加载其他源码文件模块。
源码文件的扩展名为 .rs
。
一个源码文件就是指一个模块,通过源码文件中引用 模块 的条目从外部定义了模块的名称。 crate 的名称通过属性或外部定义。 一个模块文件中可以嵌套定义子模块。
每个源码文件 (即模块) 包含了零个或多个 条目 ,对于添加的模块 属性 往往会影响编译器的行为。 顶层模块可以添加应用于 crate 的属性。
#![allow(unused)] fn main() { // 以下是添加到顶层模块的属性 // 指定 crate 名称 #![crate_name = "projx"] // 指定输出 crate 制品的类型 #![crate_type = "lib"] // 这个属性可以添加到子模块中 #![warn(non_camel_case_types)] // 开启警告。 }
字节顺序标记
可选的 UTF8 字节顺序标记 (UTF8BOM 产生式) 表明该文件使用 UTF8 编码。 只能出现在源码文件的开头,是给解释器实现的预留,会被编译器忽略。
执行注解
源码文件可以包含 执行注解 ,表明操作系统该使用哪个程序来执行此文件,相当于以脚本方式执行。 执行注解只能出现在文件开头,在可选的 UTF8BOM 之后。 同样是给解释器的预留,会被编译器忽略。 例如:
#!/usr/bin/env rustx
fn main() {
println!("Hello!");
}
对于执行注解语法,存在限制以避免与 属性 混淆。
#!
字符忽略 空白 及注释后,不能紧跟 [
标记,否则,会被编译器当成属性。
预定义 和 no_std
本节已移至 预定义章节 。
Main 函数
如果要把 crate 编译成可执行文件,需要包含一个 main
函数 。
此 main
函数,不接受任何参数,不能声明任何 trait 或生命周期约束,也不能有任何 where
从句,且返回类型必须实现 Termination
trait。
fn main() {}
fn main() -> ! { std::process::exit(0); }
fn main() -> impl std::process::Termination { std::process::ExitCode::SUCCESS }
注意: 标准库中具有
Termination
实现的类型包括:
()
!
Infallible
ExitCode
Result<T, E> where T: Termination, E: Debug
no_main
属性
no_main
属性可以应用于 crate 顶层模块,从而可以禁用在编译为可执行二进制文件时 main
符号的输出。
从而已经定义了 main
函数的 carte 可以被其他 crate 链接。
crate_name
属性
crate_name
属性 可以应用于 crate 顶层模块,用来指定 crate 名称,语法为 元名称值字符串 。
#![allow(unused)] #![crate_name = "mycrate"] fn main() { }
该名称不能为空,只能包含 Unicode 字母数字 或 _
(U+005F) 字符。
在解释器中,同样有所区分。应该先作静态检查,例如语法分析、类型检查和代码分析,然后执行。
crate 编译模型类似于 ECMA-335 CLI 模型中的 assembly , SML/NJ 编译管理器中的 library ,Owens 和 Flatt 模块系统中的 unit,或 Mesa 中的 configuration 。