Немного о модульной системе языка Rust(часть 2)

в 18:00, , рубрики: Rust, Программирование
Продолжаем

Хорошо. Давайте теперь попробуем подключить в 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

Источник

Поделиться новостью

* - обязательные к заполнению поля