Я хочу иметь модуль с несколькими структурами в нем, каждая в своем собственном файле. На Math
примере модуля:
Math/
Vector.rs
Matrix.rs
Complex.rs
Я хочу, чтобы каждая структура находилась в одном модуле, который я бы использовал из своего основного файла, например:
use Math::Vector;
fn main() {
// ...
}
Однако модульная система Rust (которая сначала немного сбивает с толку) не предоставляет очевидного способа сделать это. Кажется, это позволяет вам хранить весь модуль в одном файле. Это не по-деревенски? Если нет, то как мне это сделать?
foo::bar::Baz
должна быть определена вfoo/bar.rs
илиfoo/bar/mod.rs
.Ответы:
Модульная система Rust на самом деле невероятно гибка и позволит вам раскрыть любую структуру, которую вы хотите, скрывая, как ваш код структурирован в файлах.
Я думаю, что ключевым моментом здесь является использование
pub use
, которое позволит вам повторно экспортировать идентификаторы из других модулей. Прецедент этого есть вstd::io
ящике Rust, где некоторые типы из подмодулей реэкспортируются для использования вstd::io
.Чтобы адаптировать ваш пример, мы могли бы начать с этой структуры каталогов:
Вот ваш
main.rs
:И ваш
src/lib.rs
:И наконец
src/vector.rs
:И здесь происходит волшебство. Мы определили подмодуль,
math::vector::vector_a
который имеет некоторую реализацию особого вида вектора. Но мы не хотим, чтобы клиенты вашей библиотеки заботились о наличииvector_a
подмодуля. Вместо этого мы хотели бы сделать его доступным вmath::vector
модуле. Это делается с помощьюpub use self::vector_a::VectorA
, который повторно экспортируетvector_a::VectorA
идентификатор в текущий модуль.Но вы спросили, как это сделать, чтобы можно было поместить свои специальные векторные реализации в разные файлы. Это то, что
mod vector_b;
делает линия. Он указывает компилятору Rust искатьvector_b.rs
файл для реализации этого модуля. И, конечно же, вот нашsrc/vector_b.rs
файл:С точки зрения клиента, тот факт, что
VectorA
иVectorB
определены в двух разных модулях в двух разных файлах, совершенно непрозрачен.Если вы находитесь в том же каталоге, что и
main.rs
, вы сможете запустить его с помощью:В целом, глава «Ящики и модули» в книге Rust довольно хороша. Примеров много.
Наконец, компилятор Rust также автоматически просматривает подкаталоги. Например, приведенный выше код будет работать без изменений с этой структурой каталогов:
Команды для компиляции и запуска также остаются прежними.
источник
math::Vec2
вместоmath::vector::Vec2
. (То есть та же концепция, но на один модуль глубже.)Правила модуля Rust:
Файл matrix.rs 1 в каталоге math - это просто модуль
math::matrix
. Это просто. То, что вы видите в своей файловой системе, вы также найдете в исходном коде. Это взаимно однозначное соответствие путей к файлам и путей к модулям 2 .Таким образом, вы можете импортировать структуру
Matrix
с помощьюuse math::matrix::Matrix
, потому что структура находится внутри файла matrix.rs в каталоге math. Не счастлив? Вы бы предпочлиuse math::Matrix;
очень многое, не так ли? Это возможно. Повторно экспортируйте идентификаторmath::matrix::Matrix
в math / mod.rs с помощью:Есть еще один шаг, чтобы заставить это работать. Rust требуется объявление модуля для загрузки модуля. Добавьте
mod math;
в main.rs. Если вы этого не сделаете, вы получите сообщение об ошибке от компилятора при импорте, например:Намек здесь вводит в заблуждение. Нет необходимости в дополнительных ящиках, за исключением того, что вы действительно собираетесь написать отдельную библиотеку.
Добавьте это в начало main.rs:
Декларация модуля также для необходимых подмодулей
vector
,matrix
иcomplex
, посколькуmath
необходимо загрузить их повторно экспортировать их. Реэкспорт идентификатора работает только в том случае, если вы загрузили модуль идентификатора. Это значит, что для реэкспорта идентификатораmath::matrix::Matrix
нужно написатьmod matrix;
. Вы можете сделать это в math / mod.rs. Поэтому создайте файл с таким содержимым:Аааи все готово.
1 Имена исходных файлов в Rust обычно начинаются со строчной буквы. Вот почему я использую matrix.rs, а не Matrix.rs.
2 Явы разные. Вы
package
тоже объявляете путь с помощью . Это избыточно. Путь уже очевиден из местоположения исходного файла в файловой системе. Зачем повторять эту информацию в объявлении вверху файла? Конечно, иногда проще быстро взглянуть на исходный код, чем выяснить расположение файла в файловой системе. Я могу понять людей, которые говорят, что это менее запутанно.источник
Пуристы Rusts, вероятно, назовут меня еретиком и возненавидят это решение, но это намного проще: просто сделайте каждую вещь в отдельном файле, а затем используйте макрос « include! » В mod.rs:
Таким образом, вы не получите дополнительных вложенных модулей и избежите сложных правил экспорта и перезаписи. Просто, эффективно, без суеты.
источник
use super::*
). Вы не можете скрыть код от других файлов (что важно для небезопасного использования безопасных абстракций)Хорошо, некоторое время боролся с моим компилятором и, наконец, заставил его работать (спасибо BurntSushi за указание
pub use
.main.rs:
математика / mod.rs:
math / vector.rs
Таким же образом можно добавить и другие структуры. ПРИМЕЧАНИЕ: скомпилирован с помощью 0.9, а не master.
источник
mod math;
вmain.rs
паре вашуmain
программу с вашей библиотекой. Если вы хотите, чтобы вашmath
модуль был независимым, вам нужно скомпилировать его отдельно и связать с нимextern crate math
(как показано в моем ответе). В Rust 0.9 возможно, чтоextern mod math
вместо этого используется синтаксис .Я хотел бы добавить сюда, как вы включаете файлы Rust, когда они глубоко вложены. У меня такая структура:
Как получить доступ
sink.rs
илиtoilet.rs
откудаmain.rs
?Как уже упоминалось, Rust не знает файлов. Вместо этого он видит все как модули и подмодули. Чтобы получить доступ к файлам в каталоге ванной комнаты, вам нужно экспортировать их или поставить наверх. Вы делаете это, указывая имя файла с каталогом, к которому вы хотите получить доступ, и
pub mod filename_inside_the_dir_without_rs_ext
внутри файла.Пример.
Создайте файл с именем
bathroom.rs
внутриhome
каталога:Экспортируйте имена файлов:
Создайте файл с именем
home.rs
рядом сmain.rs
pub mod
файл bathroom.rsВ пределах
main.rs
use
также могут использоваться операторы:Включение других родственных модулей (файлов) в подмодули
В случае, если вы хотите использовать
sink.rs
fromtoilet.rs
, вы можете вызвать модуль, указавself
илиsuper
ключевые слова .Окончательная структура каталогов
Вы получите что-то вроде этого:
Приведенная выше структура работает только с Rust 2018 и новее. Следующая структура каталогов также действительна для 2018 года, но именно так в 2015 году работал.
В котором
home/mod.rs
то же, что./home.rs
иhome/bathroom/mod.rs
то же самое, что иhome/bathroom.rs
. Rust внес это изменение, потому что компилятор запутается, если вы включите файл с тем же именем, что и каталог. Версия 2018 года (показанная первой) исправляет эту структуру.См. Это репо для получения дополнительной информации и это видео на YouTube для общего объяснения.
И последнее ... избегайте дефисов!
snake_case
Вместо этого используйте .Важная заметка
Вы должны направить все файлы вверх, даже если глубокие файлы не требуются для файлов верхнего уровня.
Это означает, что для
sink.rs
обнаруженияtoilet.rs
вам потребуется использовать их, используя описанные выше методы вплоть доmain.rs
!Другими словами, делать
pub mod sink;
илиuse self::sink;
внутри неtoilet.rs
будет работать, если вы не раскрыли их полностью доmain.rs
!Поэтому всегда не забывайте ставить файлы наверх!
источник