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

от автора


Продолжаем

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

ссылка на оригинал статьи http://habrahabr.ru/post/275533/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *