Avatar ·

Как подключить модуль из другого файла в том же проекте на Rust?

Всем привет! Я только начал изучать Rust и столкнулся с проблемой организации кода. Мой проект быстро разрастается, и я хочу разбить его на несколько файлов, но не понимаю, как правильно импортировать функции и структуры из одного файла в другой. Вот моя текущая структура. У меня есть `main.rs` и я создал файл `math_utils.rs` в той же папке `src/`. В `math_utils.rs` я определил простую функцию: ```rust // math_utils.rs fn add(x: i32, y: i32) -> i32 { x + y } ``` А в `main.rs` я пытаюсь её вызвать: ```rust // main.rs fn main() { let result = add(5, 3); // Ошибка: cannot find function `add` in this scope println!("Result: {}", result); } ``` Я попробовал добавить `mod math_utils;` в начало `main.rs`, но это не помогло. Компилятор выдаёт ошибку, что модуль `math_utils` не найден, хотя файл лежит рядом. Я также читал про ключевое слово `use`, но всё равно не могу заставить код работать. Подскажите, пожалуйста, как правильно организовать модули в Rust? Нужно ли что-то менять в `Cargo.toml`? Почему простое создание файла и `mod` не работают? Заранее спасибо за помощь! <<>>

Как правильно подключать модули в Rust: пошаговое руководство

Проблема, с которой вы столкнулись, очень типична для новичков. В Rust система модулей работает не так, как в Python или JavaScript. Давайте разберёмся по порядку.

Шаг 1. Объявление модуля с помощью mod

Когда вы пишете mod math_utils; в main.rs, вы говорите компилятору: "Ищи файл math_utils.rs (или папку math_utils/mod.rs) и загрузи его как модуль". Это правильный первый шаг. Но после этого функции внутри модуля не становятся автоматически доступными — они находятся в пространстве имён модуля.

Исправленный main.rs:

// main.rs
mod math_utils; // Объявляем модуль

fn main() {
    // Теперь нужно обращаться через имя модуля
    let result = math_utils::add(5, 3);
    println!("Result: {}", result);
}

Шаг 2. Публичность (pub)

Даже после этого код не скомпилируется. В Rust всё по умолчанию приватное. Функция add внутри модуля math_utils не видна снаружи. Нужно явно сделать её публичной:

// math_utils.rs
pub fn add(x: i32, y: i32) -> i32 {  // Добавили pub
    x + y
}

Шаг 3. Сокращение пути с помощью use

Если вам надоело каждый раз писать math_utils::add, используйте use:

// main.rs
mod math_utils;
use math_utils::add; // Импортируем функцию в текущую область видимости

fn main() {
    let result = add(5, 3); // Теперь можно вызывать напрямую
    println!("Result: {}", result);
}

Более сложная структура: подмодули и папки

Когда проект растёт, вы можете захотеть создать папку для модуля. Например, структура:

src/
├── main.rs
└── math/
    ├── mod.rs   // Главный файл модуля math
    └── advanced.rs // Дочерний модуль

В math/mod.rs:

// math/mod.rs
pub mod advanced; // Объявляем дочерний модуль

pub fn basic_add(x: i32, y: i32) -> i32 {
    x + y
}

В math/advanced.rs:

pub fn fast_add(x: i32, y: i32) -> i32 {
    x + y
}

В main.rs:

mod math; // Объявляем корневой модуль math

use math::basic_add;
use math::advanced::fast_add;

fn main() {
    println!("Basic: {}", basic_add(1, 2));
    println!("Fast: {}", fast_add(3, 4));
}

Важные правила

  • Не нужно ничего менять в Cargo.toml. Cargo сам находит все .rs файлы в папке src/.
  • Каждый файл — это модуль. Имя файла (без .rs) становится именем модуля.
  • Точка входа — main.rs или lib.rs. Для бинарных проектов — main.rs, для библиотек — lib.rs.
  • Используйте pub для экспорта. Всё, что вы хотите сделать доступным снаружи модуля, должно быть помечено pub.
  • Для папок используйте mod.rs. Если вы создаёте папку my_module/, внутри должен быть файл mod.rs (или можно использовать my_module.rs как корневой файл, но это новый синтаксис Rust 2018).

Теперь ваш код будет работать! Если у вас остались вопросы, не стесняйтесь задавать их в комментариях.

<<>>

Альтернативный подход: использование crate:: и относительных путей

В дополнение к основному ответу, стоит упомянуть, что в Rust есть несколько способов ссылаться на модули, особенно когда у вас сложная иерархия.

Вместо того чтобы везде писать use, вы можете использовать абсолютные пути от корня крейта (crate):

// main.rs
mod math_utils;

fn main() {
    // Абсолютный путь от корня проекта
    let result = crate::math_utils::add(10, 20);
    println!("{}", result);
}

Это особенно полезно в больших проектах, где вы находитесь глубоко внутри вложенных модулей. Ключевое слово crate обозначает корень вашего проекта (то есть main.rs или lib.rs).

Также есть относительные пути с ключевыми словами self (текущий модуль), super (родительский модуль) и crate (корень). Пример:

// Внутри math/advanced.rs
use super::basic_add; // super ведёт в math/mod.rs

pub fn complex_calc(x: i32) -> i32 {
    basic_add(x, 10) * 2
}

Используйте тот стиль, который делает ваш код более читаемым и поддерживаемым. Для небольших проектов use в начале файла — это золотой стандарт.