English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Любой язык программирования, который не может организовать код, трудно углубиться в,几乎没有一个软件产品是由一个源文件编译而成的。
Все программы в этом руководстве до сих пор писались в одном файле, что делает изучение синтаксиса и концепций языка Rust более удобным.
Для проекта организация кода является важной.
В Rust есть три важных организационных концепции: контейнер, пакет, модуль.
"Контейнер" — это файл двоичной программы или библиотеки, который存在于 "пакете".
"Контейнер" имеет иерархическую структуру, корнем которой является программа, компилируемая из исходных файлов, которые начинают компилироваться при запуске компилятора.
Обратите внимание: "файл двоичного программы" не всегда является "двоичным файлом выполняемого файла", он может быть определен как файл, содержащий машинный язык целевой машины, формат файла может варьироваться в зависимости от среды компиляции.
Когда мы используем команду cargo new для создания проекта Rust, в каталоге проекта будет создан файл Cargo.toml. Сам проект — это пакет, который должен управляться с помощью файла Cargo.toml, который описывает основные данные пакета и зависимости.
Пакет может содержать не более одного библиотечного "контейнера", может содержать любое количество двоичных "контейнеров", но должен содержать по крайней мере один "контейнер" (будь то библиотечный или двоичный "контейнер").
После создания пакета с помощью команды cargo new в каталоге src будет создан исходный файл main.rs, Cargo по умолчанию делает этот файл корнем двоичного контейнера, после компиляции двоичный контейнер будет иметь то же имя, что и имя пакета.
Для инженерии программного обеспечения мы часто организуем по нормам организации, которые установлены используемым языком программирования, основная структура организационных модулов часто представляет собой дерево. Основной единицей организационной функциональности в Java являются классы, а в JavaScript организационным способом являются функции.
Эти организационные единицы современных языков могут включать друг в друга по иерархии, как структура каталогов в файловой системе. Организационные единицы в Rust — это модули (Module).
mod nation { mod government { fn govern() {} } mod congress { fn legislate() {} } mod court { fn judicial() {} } }
Это описание процедуры правового государства: страна (нация) включает правительство (правительство), парламент (конгресс) и суд (суд), которые выполняют функции управления, законодательства и юстиции. Её можно представить в виде иерархической структуры:
нация ├── правительство │ └── правительство ├── конгресс │ └── законодательство └── суд └── судебный
В файловой системе структура каталогов часто представлена слешом в строке пути, разделителем путей в Rust является ::.
Путь делится на абсолютный путь и относительный путь. Абсолютный путь начинается с ключевого слова crate. Относительный путь начинается с ключевых слов self, super или идентификатора. Например:}
crate::nation::government::govern();
Это абсолютный путь к функции govern, относительный путь можно представить как:
nation::government::govern();
Теперь вы можете попробовать определить аналогичную структуру модуля в одном файле и использовать путь в основной функции.
Если вы сделаете так, вы обязательно会发现 ошибки: модуль government и функции в нем являются частными (private), и вы не имеете права доступа к ним.
В Rust есть два простых уровня доступа: общественный (public) и частный (private).
По умолчанию, если не указан модификатор, доступ к членам модуля будет частным.
Чтобы использовать общедоступные права, необходимо использовать ключевое слово pub.
Для частных модулей доступ возможен только с уровня или ниже их, не может быть из внешней стороны.
mod nation { pub mod government { pub fn govern() {} } mod congress { pub fn legislate() {} } mod court { fn judicial() { super::congress::legislate(); } } } fn main() { nation::government::govern(); }
Этот код можно скомпилировать. Обратите внимание на метод доступа super в модуле court.
Если в модуле определен структуру, структура, а также ее поля по умолчанию являются частными. Поэтому, чтобы использовать структуру и ее поля из модуля, необходимо использовать объявление pub:
mod back_of_house { pub struct Breakfast { pub toast: String, seasonal_fruit: String, } impl Breakfast { pub fn summer(toast: &str) -> Breakfast { Breakfast { toast: String::from(toast), seasonal_fruit: String::from("peaches"), } } } } pub fn eat_at_restaurant() { let mut meal = back_of_house::Breakfast::summer("Rye"); meal.toast = String::from("Wheat"); println!("I'd like {} toast please", meal.toast); } fn main() { eat_at_restaurant() }
Результат выполнения:
I'd like Wheat toast please
Элементы枚ерации могут содержать поля, но не обладают подобными свойствами:
mod SomeModule { pub enum Person { King { name: String }, Quene } } fn main() { let person = SomeModule::Person::King { name: String::from("Blue") }; match person { SomeModule::Person::King {name} => { println!("{}", name); } _ => {} } }
Результат выполнения:
Blue
Разработчики, использовавшие Java, часто очень не любят outermost class блок - его имя совпадает с именем файла, потому что он представляет контейнер файла, хотя это и хлопотно, но мы должны написать его, чтобы подчеркнуть 'Этот класс содержится в файле'.
Но у этого есть свои преимущества: по крайней мере, это позволяет разработчику отчетливо осознавать существование классовых оберток, и можно четко описать наследственные отношения классов.
В Rust модули похожи на классы в Java, но в начале файла можно написать основную функцию, как это объяснить?
Содержимое каждого файла Rust представляет собой 'трудно обнаруживаемый' модуль.
Давайте используем два файла, чтобы продемонстрировать это:
Результат выполнения:
Это главный модуль. Это 2-й модуль.
Ключевое слово 'use' позволяет ввести идентификатор модуля в текущий область видимости:
mod nation { pub mod government { pub fn govern() {} } } use crate::nation::government::govern; fn main() { govern(); }
Этот код может быть скомпилирован.
Потому что ключевое слово use импортирует идентификатор govern в текущий модуль, его можно использовать напрямую.
Таким образом, мы решаем проблему чрезмерно длинного пути модуля.
Конечно, в некоторых случаях могут встречаться два одинаковых имени, и их также необходимо импортировать. В этом случае мы можем использовать ключевое слово as для добавления alias к идентификатору:
mod nation { pub mod government { pub fn govern() {} } pub fn govern() {} } use crate::nation::government::govern; use crate::nation::govern as nation_govern; fn main() { nation_govern(); govern(); }
Здесь есть две функции govern, одна из которых находится в nation, а другая - в government. Мы используем as, чтобы дать alias для функции из nation - nation_govern. Два имени могут использоваться одновременно.
Ключевое слово use можно использовать вместе с ключевым словом pub:
mod nation { pub mod government { pub fn govern() {} } pub use government::govern; } fn main() { nation::govern(); }
Словарь официальной стандартной библиотеки Rust:https://doc.rust-lang.org/stable/std/all.html
После изучения концепций этой главы мы можем легко импортировать системные библиотеки для удобного разработки программ.
use std::f64::consts::PI; fn main() { println!("{}", (PI / 2.0).sin()); }
Результат выполнения:
1
Все системные библиотечные модули по умолчанию импортируются, поэтому при использовании их нужно только использовать ключевое слово use для упрощения пути, чтобы можно было удобно использовать.