Крейты и исходные файлы
Syntax
Crate →
InnerAttribute*
Item*
Note
Хотя Rust, как и любой другой язык, может быть реализован как интерпретатором, так и компилятором, единственная существующая реализация — это компилятор, и язык всегда проектировался для компиляции. По этим причинам данный раздел предполагает использование компилятора.
Семантика Rust подчиняется фазовому разграничению между временем компиляции и временем выполнения.1 Семантические правила, имеющие статическую интерпретацию, определяют успех или неудачу компиляции, в то время как семантические правила, имеющие динамическую интерпретацию, определяют поведение программы во время выполнения.
Модель компиляции сосредоточена вокруг артефактов, называемых крейтами. Каждый процесс компиляции обрабатывает один крейт в исходной форме и, в случае успеха, производит один крейт в бинарной форме: либо исполняемый файл, либо библиотеку того или иного вида.2
Крейт — это единица компиляции и линковки, а также версионирования, распространения и загрузки во время выполнения. Крейт содержит дерево вложенных областей видимости модулей. Верхний уровень этого дерева — это модуль, который является анонимным (с точки зрения путей внутри модуля), и любой элемент в пределах крейта имеет канонический путь модуля, обозначающий его расположение в пределах дерева модулей крейта.
Компилятор Rust всегда вызывается с одним исходным файлом в качестве входных данных и
всегда производит один выходной крейт. Обработка этого исходного файла может
привести к загрузке других исходных файлов в качестве модулей. Исходные файлы имеют
расширение .rs.
Исходный файл Rust описывает модуль, имя и расположение которого — в дереве модулей текущего крейта — определяются извне исходного файла: либо явным объявлением модуля в ссылающемся исходном файле, либо именем самого крейта.
Каждый исходный файл является модулем, но не каждому модулю нужен свой собственный исходный файл: определения модулей могут быть вложены в один файл.
Каждый исходный файл содержит последовательность из нуля или более определений Элементов и может опционально начинаться с любого количества атрибутов, которые применяются к содержащему модулю, большинство из которых влияют на поведение компилятора.
Анонимный модуль крейта может иметь дополнительные атрибуты, которые применяются к крейту в целом.
Note
Содержимое файла может предваряться шебангом.
#![allow(unused)] fn main() { // Указание имени крейта. #![crate_name = "projx"] // Указание типа выходного артефакта. #![crate_type = "lib"] // Включение предупреждения. // Это можно сделать в любом модуле, а не только в анонимном модуле крейта. #![warn(non_camel_case_types)] }
Функция main
Крейт, содержащий функцию main, может быть скомпилирован в исполняемый файл.
Если функция main присутствует, она не должна принимать аргументов, не должна объявлять
ограничений типов (трейтов) или времен жизни, не должна иметь where-предложений, и её возвращаемый
тип должен реализовывать типаж Termination.
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; }
Note
Типы из стандартной библиотеки, реализующие
Termination:
()!InfallibleExitCodeResult<T, E> where T: Termination, E: Debug
Неперехваченное внешнее раскручивание стека (unwinding)
Когда “внешнее” раскручивание стека (например, исключение, вставленное из кода C++, или panic! в коде Rust, использующем другой обработчик паники) распространяется за пределы функции main, процесс будет безопасно завершён. Это может принять форму аварийного завершения (abort), и в этом случае не гарантируется, что какие-либо вызовы Drop будут выполнены, а вывод ошибки может быть менее информативным, чем если бы среда выполнения была завершена “нативной” Rust-паникой.
Для получения дополнительной информации см. документацию по панике.
Атрибут no_main
Атрибут no_main может быть применён на уровне крейта, чтобы отключить генерацию символа main для исполняемого бинарного файла. Это полезно, когда какой-либо другой связываемый объект определяет main.
Атрибут crate_name
Атрибут crate_name может быть применён на уровне крейта, чтобы указать
имя крейта с помощью синтаксиса MetaNameValueStr.
#![allow(unused)] #![crate_name = "mycrate"] fn main() { }
Имя крейта не должно быть пустым и должно содержать только Юникодные алфавитно-цифровые
символы или символы _ (U+005F).
-
Это разграничение также существовало бы и в интерпретаторе. Статические проверки, такие как синтаксический анализ, проверка типов и линтеры, должны происходить до выполнения программы независимо от того, когда она выполняется. ↩
-
Крейт в некоторой степени аналогичен сборке (assembly) в модели ECMA-335 CLI, библиотеке в SML/NJ Compilation Manager, юниту (unit) в модульной системе Овенса и Флатта или конфигурации в Mesa. ↩