Выпуск 25. Март 2015

Про переменные и сигнатуры в Perl 6 | Содержание | Обзор CPAN за февраль 2015 г.

Модули в Perl 6

Краткий обзор основных моментов, которые полезно знать при работе с модулями в Perl 6

Тем, кто знаком с модулями в Perl 5, без труда разберутся с тем, как использовать их в Perl 6. Тем не менее, есть несколько важных отличий, которые необходимо знать перед началом работы.

Модули хранятся в файлах с тем же расширением .pm. Точно так же организуется иерархия: модуль X::Y компилятор будет искать в файле X/Y.pm в одном из предопределенных каталогов или в каталоге, указанном в опции -I при запуске из командной строки.

В теории, имена модулей не обязаны быть привязаны к файлам (а на практике сейчас имя модуля, указанное в самом модуле, похоже, вообще не используется). Однако пока про это, видимо, лучше не думать. Еще одна интересная особенность, а именно, возможность хранить и подключать один и тот же модуль, но разных версий, пока в Rakudo не реализована.

module

Модуль объявляется ключевым словом module, за которым следует название. Возможны два варианта. Объявление может быть в виде директивы в начале файла, и весь остаток файла будет телом модуля:

module X;

sub x() {
    say "X::x()";
}

Второй вариант — поместить тело модуля в блок:

module X {
    sub x() {
        say "X::x()";
    }
}

export

Переменные (my, our) и функции (sub), определяемые внутри модуля, по умолчанию не видны за его пределами. Для того, чтобы экспортировать имя, необходимо указать свойство (trait) is export:

module X;

sub x() is export {
    say "X::x()";
}

Это все, что требуется для того, чтобы функцией x() удалось воспользоваться в программе, которая будет использовать модуль. Никаких многословных конструкций и манипулирования массивами @EXPORT и @EXPORT_OK больше не требуется.

use

Подключение модуля — простая операция с помощью ключевого слова use.

Сначала создаем файл Greet.pm:

module Greet;

sub hey($name) is export {
    say "Hey, $name!";
}

А затем используем его:

use Greet;

hey("you"); # Hey, you!

Точно так же все работает, если имя модуля более сложное. В этом случае все импортируемые имена оказываются в текущей области видимости.

Файл Greet/Polite.pm с модулем Greet::Polite:

module Greet::Polite {
    sub hello($name) is export {
        say "Hello, $name!";
    }
}

И программа, его использующая:

use Greet;
use Greet::Polite;

hey("you"); # функция из модуля Greet
hello("Mr. X"); # из Greet::Polite

import

Ключевое слово use автоматически выполняет импорт имен из подключаемого модуля. Однако, если модуль определен в текущем файле в лексической области видимости (обратите внимание, что можно указать модуль локальным, написав my module), автоматический импорт не произойдет, и придется сделать его явно:

my module M {
    sub f($x) is export {
        return $x;
    }
}

import M;

say f(42);

Без принудительного импорта (import M;) обращение к функции f() из модуля приведет к ошибке. Причем импорту подвергнутся только имена, помеченные на экспорт конструкцией is export.

Обратите внимание, что импорт происходит при компиляции, поэтому имена станут доступны в программе даже выше строки про импорт:

my module M {
    . . .
}

say f(1);
import M;
say f(2);

need

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

Создаем модуль N с методом n() (метод создан как our — это важно, но без is export — а это не так важно):

module N;

our sub n() {
    say "N::n()";
}

И теперь указываем, что нужен этот модуль, а потом напрямую обращаемся к его методу:

need N;

N::n();

Последовательность use M; import M; (именно в таком порядке) аналогична одному use M;.

require

Ключевое слово require позволяет загрузить модуль не во время компиляции (как это делает use), а во время исполнения.

Для примера — модуль с единственной функцией, возвращающей сумму переданных ей аргументов:

module Math;

our sub sum(*@a) {
    return [+] @a;
}

(Звездочка в *@a нужна, чтобы Perl свернул все аргументы в один массив, и можно было бы написать sum(1, 2, 3). Без звездочки это станет синтаксической ошибкой, поскольку метод будет ожидать массив, а не три скаляра.)

Теперь подключаем модуль с помощью require и вызываем функцию:

require Math;

say Math::sum(24..42); # 627

Если попытаться вызвать Math::sum() до require, программа не сможет найти нужное имя. При этом импортировать метод, написав import Math;, тоже не получится, поскольку импорт происходит на этапе компиляции, то есть до того, как require загрузит модуль.

Заключение

Для удобства, вот список ключевых слов Perl 6, которые потребуются при работе с модулями:

  • use — загрузка и импорт на этапе компиляции;
  • need — загрузка без импорта на этапе компиляции;
  • import — импорт имен из загруженного модуля на этапе компиляции;
  • require — загрузка без импорта во время исполнения.

Андрей Шитов


Про переменные и сигнатуры в Perl 6 | Содержание | Обзор CPAN за февраль 2015 г.
Нас уже 1393. Больше подписчиков — лучше выпуски!

Комментарии к статье