Путаница с модулями в Rust при наличии main.rs и lib.rs
Понимание корневых файлов и модулей в Rust
Ваша путаница связана с тем, что main.rs и lib.rs — это два разных корневых модуля (crate roots) в Rust. Каждый из них является точкой входа для своего крейта: main.rs для исполняемого файла (binary crate), а lib.rs для библиотеки (library crate). Они не видят модули друг друга напрямую.
Когда вы пишете mod utils в lib.rs, вы объявляете модуль внутри библиотечного крейта. А когда вы пишете mod utils в main.rs, вы пытаетесь объявить модуль внутри бинарного крейта — и компилятор ищет файл src/utils.rs или директорию src/utils/mod.rs, но не находит его. Вот почему возникает ошибка.
Решение: Использование библиотеки из бинарного крейта
Чтобы использовать код из lib.rs в main.rs, вам нужно правильно организовать модули и импорты. Вот правильный подход:
Шаг 1: Определите публичный модуль в lib.rs
// src/lib.rs
pub mod utils;
pub fn add(x: i32, y: i32) -> i32 {
x + y
}
Шаг 2: Создайте файл модуля
Создайте src/utils.rs:
// src/utils.rs
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
Шаг 3: Импортируйте библиотеку в main.rs
// src/main.rs
use my_project::utils::greet;
// или use my_project::add;
fn main() {
println!("{}", greet("Alice"));
println!("2 + 3 = {}", my_project::add(2, 3));
}
Обратите внимание: по умолчанию имя крейта совпадает с именем проекта (указано в Cargo.toml в поле name). Если ваш проект называется my_project, то библиотечный крейт доступен как my_project.
Альтернатива: Всё в одном файле
Если вы не хотите разделять код на библиотеку и бинарник, просто удалите lib.rs и работайте только с main.rs:
// src/main.rs
mod utils;
fn main() {
println!("{}", utils::greet("Bob"));
}
mod utils {
pub fn greet(name: &str) -> String {
format!("Hi, {}!", name)
}
}
Ключевые моменты для запоминания
- Корневые модули:
main.rsиlib.rs— это разные корни. Они не видят модули друг друга напрямую. - Использование библиотеки: Чтобы использовать функции из
lib.rsвmain.rs, импортируйте их через имя крейта:use crate_name::module::function. - Публичность: Модули и функции, которые вы хотите использовать из другого крейта, должны быть помечены как
pub. - Файловая система: Модуль
mod utils;ожидает найти файлsrc/utils.rsилиsrc/utils/mod.rs.
Если вы хотите, чтобы бинарный крейт зависел от библиотечного, но при этом они были в одном проекте — это стандартный паттерн. Вы также можете добавить в Cargo.toml секцию [[bin]] для явного указания путей, но стандартная структура работает отлично.
Другой подход: Использование модулей через папки
Если у вас много модулей, удобнее организовать их в отдельные папки. Вместо одного файла utils.rs создайте папку utils/ с файлом mod.rs внутри:
src/
├── main.rs
├── lib.rs
└── utils/
└── mod.rs
В lib.rs объявите модуль как обычно:
pub mod utils;
В utils/mod.rs определите функции и подмодули:
pub fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
pub mod inner; // если нужен подмодуль
Тогда в main.rs импорт будет таким же: use my_project::utils::greet;. Этот подход масштабируется лучше, когда модулей много, и помогает избежать длинных файлов.
Ещё один совет: если вы хотите использовать lib.rs исключительно как библиотеку, а main.rs — как точку входа, можно сделать main.rs очень коротким, просто вызывая функции из библиотеки. Так вы отделяете логику от исполнения.
Ответов пока нет.
Войдите чтобы оставить ответ