Продолжаем
Хорошо. Давайте теперь попробуем подключить в main.rs ещё один модуль — number2. И в нём мы определим функцию one2(), которая возвращает не «one», а «one2».
Подключаем:
use num::number;
use num::number2;
Командуем… Замечательно, но если у нас в корневом модуле num подключено штук 20 других модулей? Не будем же мы постоянно писать:
use num::number;
use num::number2;
use num::next;
...
Для этого мы можем написать так:
use num::{number, number2, next, ...}; // Все разом!
Перечисляем в фигурных скобках через запятую необходимые нам модули, объявленные в модуле num(num — это src/lib.rs). Заканчиваем фигурной скобкой и точкой с запятой. И главное — работает!!!
Вопрос: а можем ли мы использовать те функции из модулей number и number2 в самом модуле num? давате попробуем:
1) Пишем в модуле num функцию libfn():
pub fn libfn() {
println!("{} + {} = 2",number::one(), number::one()); // one + one = 2
}
3) Далее в main.rs пишем:
extern crate num;
fn main() {
num::libfn(); // Вызываем libfn().
}
И командуем…
выход:
one + one2 = 2
Работает — значит можем. При этом я использовал путь к функциям относительно текущего местоположения. А можем ли мы использовать их только по имени(без пути)? Пробуем:
1) Пишем в модуль num над объявленными модулями(
Rust требует, чтобы объявления use шли в первую очередь
) строки:
use self::number::one; // Мы как бы вводим их в нашу область видимости.
use self::number2::one2;
2) + изменяем функцию:
println!("{} + {} = 2",one(), one2()); // one + one2 = 2
И командуем… Работает.
Что можно сказать о self? По умолчанию объявления use используют абсолютные
пути, начинающиеся с корня контейнера. self, напротив, формирует эти пути относительно
текущего места в иерархии. У use есть еще одна особая форма: вы можете использовать use
super::, чтобы подняться по дереву на один уровень вверх от вашего текущего
местоположения. Некоторые предпочитают думать о self как о., а о super как о…, что
для многих командных оболочек является представлением для текущей директории и для
родительской директории соответственно.
Таким образом, я, наверно, могу использовать функции one() и one2() в main.rs, ведь модуль num в нашей облати видимости… Пишем в main.rs:
extern crate num;
fn main() {
println!("{}",one()); // Ведь одна из двух должна работать.
println!("{}",num::one());
}
Но возникают ошибки:
error: unresolved name `one`
error: unresolved name `num::one`
И что не так? Пробуем исправить. Пишем в модуль num вместо
use self::number::one;
use self::number2::one2;
это:
pub use self::number::one;
pub use self::number2::one2;
Запускаем:
$ cargo run
Ага! теперь только одна ошибка:
error: unresolved name `one`
Ну теперь-то понятно. Мы сделаали видимыми функции one() и one2() в модуле num, но чтобы до них добраться нам нужно пройти через модуль num:
num::one()
Значит с помощью use мы сделали их видимыми в модуле, но чтобы мы могли ими пользоваться в main.rs их надо сделать публичными!
В н е use, пути относительны: foo::bar() ссылаться на функцию внутри foo
относительно того, где мы находимся. Если же используется префикс ::, то ::foo::bar()
будет ссылаться на другой foo, абсолютный путь относительно корня контейнера.
Надобно теперь испытать use super::, а потом ::.
Пишем в number/mod.rs вверху:
use super::libfn2;
И ниже добавляем функцию:
pub fn superfn() {
libfn2(); // Вызов llibfn2().
}
Добавляем в модуль num функцию libfn2():
fn libfn2() {
println!("super works");
}
Пишем в main.rs:
fn main() {
num::number::superfn(); // Вызов superfn().
}
И компилируем.Работает. А что, если мы перед use super поставим pub? Пробуем:
Дописываем в number/mod.rs слово pub. Дописываем в модуль num перед функцией libfn2() слово pub( чтобы мы могли ею воспользоваться). Изменяем в main.rs имя функции:
num::number::libfn2();
Компилируем. Работает. Я в восторге!!! Ну, а если мы вместо pub use super::libfn2; напишем:
1) pub use super::libfn;
2) Удалим функцию libfn2(); // Т.к. модуль не видет функцию libfn2() он выдаст ошибку.
3) Изменим в main.rs имя вызываемой функции:
num::number::libfn();
Запускаем. Работает…
Теперь ::
Если подумать, то можно сделать вывод, что
pub use ::libfn;
и
pub use super::libfn;
в данном случае аналогичны, но нам всё же надо проверить. Переписываем, компилируем и запускаем. Мы оказались правы: работает.
Ну, на этом пока всё. До встречи, читатель.
Литература:
The Rust Reference (английский)
The Rust Programming Language (английский)
The Rust Programming Language (русский)
Автор: no_face