2013-07-29 4 views
6

Если у меня есть модуль с методами a и b и хотите экспортировать их я:Что такое @ISA в Perl?

use Exporter; 
our @ISA = qw (Exporter); 
our @EXPORT = qw (a b); 

То, что я не понимаю, что делает эту линию:
our @ISA = qw (Exporter); делать?

+1

См. 'Perldoc perlobj' и' perldoc perltoot'. –

+2

Не имеет смысла экспортировать методы?!? Вы имеете в виду «subs»? – ikegami

ответ

3

Переменная пакета @ISA используется для указания наследования между классами. Вам не рекомендуется манипулировать этой переменной самостоятельно. Если вы хотите, чтобы наследовать от другого класса, сделать

use parent 'Parent::Class'; 

или предварительно v10.1:

use base 'Parent::Class'; 

В данном конкретном случае, унаследовав от Exporter делает метод import доступны. Ваш код можно переписать как.

use parent 'Exporter'; 
our @EXPORT = qw/a b/; 

Метод import вызывается автоматически, когда ваш модуль use d, и может экспортировать символы в использовании пакета.


Почему с помощью @ISA вручную плохо:

  • Не назначайте на @ISA: Другие модули могут быть уже добавлены записи к нему; это перепишет их. Поэтому push @ISA, "Some::Class".

  • Избегайте модификации @ISA во время выполнения. Лучше указать отношения наследования как можно раньше (во время разбора или после начальной компиляции), чтобы ваш модуль мог использоваться там без ограничений. Вы можете обернуть его в блоке BEGIN или CHECK, как

    BEGIN { 
        push @ISA, "Some::Class"; 
    } 
    

Наследование через parent делает это гораздо проще. parent также скомпилирует запрошенный модуль, если он еще не загружен: нет необходимости в use Some::Class.

+0

Но зачем мне это явно писать? После этого я не использую его – Jim

+0

@ Jim Я не понимаю. Модуль Exporter позволяет экспортировать символы из вашего пакета, когда он «используется». Это реализовано с помощью метода 'import'. Вы можете самостоятельно написать (подвергнуть ошибкам) ​​или наследовать универсальную реализацию от «Экспортера». Наследование внутренне представлено массивом '@ ISA'. – amon

3

Он инструктирует Perl искать в модуле Exporter методы, когда он не может найти их в вашем пакете. Обычным методом, который вы хотите наследовать от Exporter, является его метод import, в котором происходит копирование экспортированных символов вашего модуля в вызывающий пакет.

От perlobj:

Каждый пакет содержит специальный массив под названием @ISA. Массив @ISA содержит список родительских классов этого класса, если таковой имеется. Этот массив проверяется, когда Perl делает разрешение метода, которое мы рассмотрим позже.

Например, это ошибка, потому что Perl будет пытаться вызвать несуществующую подпрограмму Foo::some_method:

sub Bar::some_method { 42 } 
my $obj = bless {}, 'Foo'; 
$obj->some_method; 

@ISA переменных в пакете говорит Perl искать метод в других пакетах, поэтому этот код будет работать и вызывать метод Bar::some_method.

sub Bar::some_method { 42 } 
my $obj = bless {}, 'Foo'; 
@Foo::ISA = qw(Bar); 
$obj->some_method; 

Практическое применение для этого является наследованием.

Как известно, редко требуется установить @ISA. Прагма parent (и более старая, теперь обескураженная прагма base) объявляет отношения наследования и задает для вас эту переменную.

11

массив @Foo::ISA - глобальная переменная, которая содержит классы, из которых наследуется класс Foo.

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

Если вы хотите, чтобы объявить отношения наследования, лучший способ сделать это является

use parent 'Exporter'; 

который щипает @ISA за кулисами для вас, а также делает некоторые другие полезные вещи.

В вашем случае, когда вы делаете

our @ISA = qw(Exporter) 

вы объявить свой класс как подкласс Exporter. Класс Exporter предоставляет метод, называемый import. Зачем вам это нужно? Потому что, когда вы говорите

use MyClass; 

Что происходит на самом деле:

BEGIN { 
    require 'MyClass.pm'; 
    MyClass->import; 
}; 

Метод import автоматически вызывается каждый раз, когда кто-то use твой класс. Этот метод может делать все, что вы хотите. (Вы можете написать свой собственный import, если хотите), но обычно он используется для импорта символов в пространство имен вызывающего. Вот что делает Exporter.

Однако, Exporter также экспортирует собственный метод import, поэтому вам фактически не нужно наследовать его. (Это было исправлено займет слишком много времени назад.) Итак, теперь вы можете просто сказать

use Exporter qw(import); 

и ваш пакет получит метод import без путаницы с @ISA на всех.

6

Think объект предназначенный здесь.

Подумайте об экспортере не как о модуле, а как о класс.Подумайте о ISA как о значении «есть», как в «Мой модуль является подклассом экспортера«.

Что вы делаете, это объявление вашего модуля как подкласса класса Exporter, что означает, что вы можете использовать метод класса Exporter , который является полезным.

Чтобы действительно объяснить, что делает Экспортер, вы должны понимать, что Perl использует пространство имен. Представьте, что ваша программа имеет переменную под названием $total, но также и модуль, который вы используете. Ваша переменная $total будет мешать переменной $total модуля.

Чтобы предотвратить это, Perl использует пространства имен. Ваша программа работает в пространстве имен от main. Ваши модули используют функцию package, чтобы объявить новое пространство имен . Теперь вы и ваш модуль можете безопасно использовать переменную под названием $total. В вашей программе это действительно $main::total, а в пакете это $ Package :: Name :: total . If you want to use something from one _namespace_ in another, you can prepend the _namespace_ on it. Think of the $ Файл :: Найти :: name and $ Файл :: Найти :: dir variables you have when you use Файл :: Найти`.

Метод import экспортера копирует ваши подпрограммы (и если вы этого желаете, переменные) из вашего пространства имен в текущее пространство имен. Представьте, используя модуль File::Copy без возможности копия над подпрограммой copy в ваше основное пространство имен. Вы можете все еще использовать его, но вы должны дать ему имя пространства имен на нем:

use File::Copy; 

... 

File::Copy::copy($from_file, $to_file); 

Благодаря Exporter (и метод импорта), любые подпрограммы вы положили в свои пакеты @EXPORT массив скопированные к текущему пространству имен. Таким образом, вы можете получить доступ к File :: Copy s copy` подпрограммой, как это:

use File::Copy; 

... 

copy ($from_file, $to_file); 

Это также объясняет, почему вы должны объявить все эти переменные, как our и не my. Переменные my: лексически ограничены и не могут быть доступны за пределами того места, где они были объявлены. Переменные пакета (например, $File::Find::name) могут быть. Для Exporter, чтобы найти ваши @EXPORT, и @EXPORT_OK массивов, это должно быть пакет переменные.

Теперь приходит желательность экспортирующих функций ...

Самые старые модули, которые мы знаем и любим экспортные подпрограммы волей-неволей. Вы используете File :: Copy, File :: Path, File :: Find и имеете немедленный доступ к их подпрограммам. Это связано с тем, что они помещают свои подпрограммы в массив @EXPORT. Это было когда-то считалось желательным, потому что оно сразу же предоставило вам эти функции.

Новые модули, такие как File::Temp требуют объявить подпрограммы, которые вы хотите импортировать:

use File::Temp qw(tempdir); 

... 
my $temp_dir = tempdir; 

Если у меня не было, что qw(tempdir), я не мог использовать функцию tempdir.

Это считается вежливым. Модуль запрашивает ваше разрешение на импорт этой функции. Это делается путем помещения подпрограмм в @EXPORT_OK. Они будут экспортироваться только по запросу.

Это лучше, потому что вам не нужно импортировать все, только то, что вам нужно. И вы документируете, где эти функции определены.

Объектно-ориентированные модули не экспортируют ничего вообще и не требуют использования Экспортера. Прошло много времени с тех пор, как я написал модуль, который использует Exporter.

- Мы говорим о пакет переменных здесь. Переменные пакета видны повсюду.

Смежные вопросы