Crate和源码文件

语法
Crate :
   UTF8BOM?
   执行注解?
   内部属性*
   条目*

词法
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 实现的类型包括:

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) 字符。

1

在解释器中,同样有所区分。应该先作静态检查,例如语法分析、类型检查和代码分析,然后执行。

2

crate 编译模型类似于 ECMA-335 CLI 模型中的 assembly , SML/NJ 编译管理器中的 library ,Owens 和 Flatt 模块系统中的 unit,或 Mesa 中的 configuration