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

в 8:15, , рубрики: Rust, Программирование

Чуть-чуть о статье

В этой статье будет идти речь о самых основных способах использования модулей в данном языке (используемая ОС: Linux). Всем известно, что лучший способ запомнить информацию надолго — это предоставить её кому-либо в виде лекции. Для этого и была написана данная статья — чтобы помочь самому себе, но буду очень рад, если она поможет и тебе, читатель.

Корневой модуль

Давайте создадим контейнер (библиотеку) для хранения модулей (NAME — имя контейнера):

$ cargo new LNAME
$ cd LNAME/

И вот что мы получили в нашем контейнере LNAME:

	./
	../
	Cargo.toml
	src/
	|------  ./
	|------  ../
	'------  lib.rs

У всех наших модулей должен быть корневой модуль, которым является файл LNAME/src/lib.rs — он был создан автоматически. Последующие модули(суб-модули) будут «разрастаться» начитая с корневого модуля, как дерево. Мы обращаемся к суб-модулям с помощью нотации ::.В модулях мы будем хранить функции, которые возвращают строки. Пишем в файле lib.rs:

fn one() -> String {
	"one".to_string()	// Функция возвращает строку "one".
}

ОК. Теперь создаём новый контейнер, который будет хранить исполняемый файл(ENAME — имя контейнера для храниния исполняемого файла):

$ cargo new ENAME --bin
$ cd EMANE

Чтобы мы могли использовать наш корневой модуль, нам необходимо в файл Cargo.toml контейнера EMANE записать:


[lib]
name = "имя_для_обращения"

С помощью этого имени мы будем обращаться к нашему корневому модулю(далее вместо имя_для_обращения будет num). Мы как бы присваиваем нашему корневому модулю имя.

Продолжаем писать:

path = "путь_к_нашему_модулю"	

«путь_к_нашему_модулю» — это путь к модулю lib.rs относительно местоположения файла, который мы редактируем.

И пишем в main.rs следующее:

extern crate num;     // Импортируем контейнер num для получения функции one().

fn main() {
	println!("{} - 1",num::one());   // Вызываем функцию one() из модуля num.
}

И запускаем:

$ cargo run

Ошибка! Прочитав пояснение компилятора, вы можете сделать вывод, что функция one() приватна. Это значит, что мы не можем использовать её в своём main.rs, но можем использовать в lib.rs. И что нам делать? Поставим перед функцией слово pub:

pub fn one() ...         // Делаем функцию публичной.

И запускаем:

$ cargo run

Выход:

one - 1

Ура! Первый шак сделан.

Всё, что стоит после num:: при вызовах функций должно быть публичным! Например:

num::newmod::oldmod::print_number()     // Вызов функции print_number()

Чтобы получить доступ к функции print_number() нам необходимо сделать все модули, находящиеся перед функцией, публичными…

Модуль в модуле

Давайте добавим модуль в корневой модуль и перенесём туда нашу функцию:

pub mod number {            //  Если хотите пользоваться функцией one(), то не забывайте ставить pub.
    pub fn one() -> String {
        "one".to_string()
    }   
}

Как вы заметили, для того, чтобы создать суб-модуль, необходимо воспользоваться словом mod(обязательно воспользуйтесь словом pub — без него нас не добраться до функции one() ).

Далее необходимо изменить файл main.rs:

extern crate num;

fn main() {
	println!("{} - 1",num::number::one());   // Вызываем функцию one() из модуля number, 
                                                                     // который находится в корневом модуле num.
}

И командуем:

$ cargo run

Выход:

one - 1

Ура! А теперь давайте попробуем объявить наш суб-модуль иначе. В lib.rs всё удаляем и пишем:

pub mod number;

Сохраняем. Если мы объявим модуль таким образом, то компилятор будет искать наш модуль либо в файле number.rs рядом с файлом, в котором находится такое объявление (в данном случае — src/number.rs), либо в файле mod.rs, который находится в папке number рядом с файлом, в котором находится такое объявление (в данном случае — src/number/mod.rs). При этом нам не надо заново объявлять модуль: это сделано при изначальном объявлении mod.!!!

Давайте рассмотрим оба варианта. Первый:

// Файл number.rs:

pub fn one() -> String {       //  Если хотите пользоваться функцией one(), то не забывайте ставить pub.
	"one".to_string()
}

// Файл main.rs(ничего не меняется):

extern crate num;

fn main() {
	println!("{} - 1",num::number::one());   // Вызываем функцию one() из модуля number, 
                                                                    // который находится в корневом модуле num.
}

Всё работает.

Второй вариант:

// Файл mod.rs:

pub fn one() -> String {  //  Если хотите пользоваться функцией one(), то не забывайте ставить pub.
	"one".to_string()
}

Файл main.rs — ничего не меняется.

Всё работает.

Используем use

Ключевое слово use позволяет импортировать модуль в нашу локальную область видимости.

Короче, если мы напишем так:

extern crate num;

use num::number;

fn main() {
	println!("{} - 1",number::one());   // Вызываем функцию one() из модуля number, 
                                                           // который находится в корневом модуле num.
}

То нам не потребуется писать полный путь при вызове: num::number::one(). Также можно импортировать саму функцию:

extern crate num;

use num::number::one;   // Пишем one без скобочек.

fn main() {
	println!("{} - 1",one());   // Вызываем функцию one() не используя num::number::
}

Но так делать не рекомендуется, т.к может возникнуть конфликт имён.

The End. Продолжение следует...

Литература:

The Rust Reference (английский)
The Rust Programming Language (английский)
The Rust Programming Language (русский)
Cargo Guide (английский)

Автор: no_face

Источник

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

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