Введение
Добро пожаловать в Packages and Crates. Этот лаба является частью Rust Book. Вы можете практиковать свои навыки Rust в LabEx.
В этом лабе мы рассмотрим пакеты и крейты, где крейт - это наименьшая единица кода, которую Rust компилятор рассматривает, и может быть бинарным крейтом или библиотечным крейтом, а пакет - это коллекция одного или более крейтов, которая предоставляет набор функций.
Packages and Crates
Первые части модульной системы, которую мы рассмотрим, - это пакеты и крейты.
Крейт - это наименьшая единица кода, которую Rust компилятор рассматривает за один раз. Даже если вы запускаете rustc вместо cargo и передаете файл исходного кода (как мы делали в "Writing and Running a Rust Program"), компилятор считает этот файл крейтом. Крейты могут содержать модули, и модули могут быть определены в других файлах, которые компилируются вместе с крейтом, как мы увидим в следующих разделах.
Крейт может быть в одном из двух форм: бинарный крейт или библиотечный крейт. Бинарные крейты - это программы, которые вы можете скомпилировать в исполняемый файл, который можно запустить, например, командную строку или сервер. Каждый из них должен иметь функцию main, которая определяет, что происходит при запуске исполняемого файла. Все крейты, которые мы создавали до сих пор, были бинарными крейтами.
Библиотечные крейты не имеют функции main и не компилируются в исполняемый файл. Вместо этого они определяют функциональность, предназначенную для использования в нескольких проектах. Например, крейт rand, который мы использовали в главе 2, предоставляет функциональность для генерации случайных чисел. Большинство времени, когда Rustaceans говорят "крейт", они имеют в виду библиотечный крейт, и они используют "крейт" взаимозаменяемо с общим концепцией программирования "библиотеки".
Корень крейта - это исходный файл, с которого начинается Rust компилятор и который составляет корневой модуль вашего крейта (мы подробно объясним модули в "Defining Modules to Control Scope and Privacy").
Пакет - это набор одного или более крейтов, который предоставляет определенный набор функций. В пакете содержится файл Cargo.toml, который описывает, как компилировать эти крейты. Cargo на самом деле является пакетом, который содержит бинарный крейт для командной строки инструмента, который вы использовали для сборки кода. Пакет Cargo также содержит библиотечный крейт, на который зависит бинарный крейт. Другие проекты могут зависеть от библиотечного крейта Cargo, чтобы использовать ту же логику, что и командная строка инструмента Cargo.
Крейт может быть в одном из двух форм: бинарный крейт или библиотечный крейт. Пакет может содержать столько бинарных крейтов, сколько вам нужно, но не более одного библиотечного крейта. Пакет должен содержать по крайней мере один крейт, будь то библиотечный или бинарный крейт.
Давайте рассмотрим, что происходит, когда мы создаем пакет. Сначала мы вводим команду cargo new my-project:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
После запуска cargo new my-project мы используем ls, чтобы увидеть, что Cargo создал. В директории проекта есть файл Cargo.toml, который дает нам пакет. Также есть директория src, которая содержит main.rs. Откройте Cargo.toml в текстовом редакторе и обратите внимание, что не упоминается src/main.rs. Cargo следуют соглашению, что src/main.rs - это корень крейта бинарного крейта с тем же именем, что и пакет. Также Cargo знает, что если в директории пакета есть src/lib.rs, то пакет содержит библиотечный крейт с тем же именем, что и пакет, и src/lib.rs - это его корень крейта. Cargo передает файлы корня крейта rustc, чтобы собрать библиотеку или бинарник.
Здесь у нас есть пакет, который содержит только src/main.rs, что означает, что он содержит только бинарный крейт с именем my-project. Если пакет содержит src/main.rs и src/lib.rs, то у него есть два крейта: бинарный и библиотечный, оба с тем же именем, что и пакет. Пакет может иметь несколько бинарных крейтов, поместив файлы в директорию src/bin: каждый файл будет отдельным бинарным крейтом.
Modules Cheat Sheet
Перед тем, как мы углубимся в детали модулей и путей, здесь мы дадим краткий справочник о том, как модули, пути, ключевое слово
useи ключевое словоpubработают в компиляторе, и как большинство разработчиков организовывают свой код. Мы будем рассматривать примеры каждого из этих правил на протяжении всей этой главы, но это отличное место для обращения, чтобы вспомнить, как работают модули.
- Начните с корня крейта: При компиляции крейта компилятор сначала ищет в файле корня крейта (обычно
src/lib.rsдля библиотечного крейта илиsrc/main.rsдля бинарного крейта) код для компиляции.- Объявление модулей: В файле корня крейта вы можете объявить новые модули; скажем, вы объявляете модуль "сад" с помощью
mod garden;. Компилятор будет искать код модуля в следующих местах:- Встроенный, внутри фигурных скобок, которые заменяют точку с запятой после
mod garden- В файле
src/garden.rs- В файле
src/garden/mod.rs- Объявление подмодулей: В любом файле, кроме файла корня крейта, вы можете объявить подмодули. Например, вы можете объявить
mod vegetables;вsrc/garden.rs. Компилятор будет искать код подмодуля в директории с именем родительского модуля в следующих местах:- Встроенный, непосредственно после
mod vegetables, внутри фигурных скобок вместо точки с запятой- В файле
src/garden/vegetables.rs- В файле
src/garden/vegetables/mod.rs- Пути к коду в модулях: Как только модуль становится частью вашего крейта, вы можете ссылаться на код в этом модуле из любого другого места в том же крейте, при условии, что правила конфиденциальности позволяют, используя путь к коду. Например, тип
Asparagusв модуле овощей сада будет найден по путиcrate::garden::vegetables::Asparagus.- Приватность vs. общедоступность: Код внутри модуля по умолчанию приватен для его родительских модулей. Чтобы сделать модуль общедоступным, объявите его с помощью
pub modвместоmod. Чтобы сделать элементы внутри общедоступного модуля также общедоступными, используйтеpubперед их объявлениями.- Ключевое слово use: В пределах области видимости ключевое слово
useсоздает ярлыки для элементов, чтобы уменьшить повторение длинных путей. В любой области видимости, которая может ссылаться наcrate::garden::vegetables::Asparagus, вы можете создать ярлык с помощьюuse crate::garden::vegetables::Asparagus;и с этого момента вам нужно будет писать толькоAsparagus, чтобы использовать этот тип в области видимости.Здесь мы создаем бинарный крейт с именем
backyard, который иллюстрирует эти правила. Директория крейта, также называемаяbackyard, содержит следующие файлы и директории:backyard ├── Cargo.lock ├── Cargo.toml └── src ├── garden │ └── vegetables.rs ├── garden.rs └── main.rsФайл корня крейта в этом случае -
src/main.rs, и он содержит:use crate::garden::vegetables::Asparagus; pub mod garden; fn main() { let plant = Asparagus {}; println!("I'm growing {:?}!", plant); }Строка
pub mod garden;сообщает компилятору включить код, который он найдет вsrc/garden.rs, который выглядит так:pub mod vegetables;Здесь
pub mod vegetables;означает, что код вsrc/garden/vegetables.rsтакже включен. Этот код выглядит так:#[derive(Debug)] pub struct Asparagus {}Теперь давайте углубимся в детали этих правил и продемонстрируем их на практике!
Резюме
Поздравляем! Вы завершили лабораторную работу по Packages and Crates. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.