Подтвердить что ты не робот

Экспорт против export_ok в perl

Я не могу понять, в чем разница/вариант использования EXPORT_OK vs EXPORT.
Большинство ресурсов упоминает что-то в следующих строках:

@Export позволяет экспортировать функции и переменные модулей в пользователей с использованием стандартного метода импорта. Таким образом, мы не необходимо создать объекты для доступа модулей к своим членам.
@EXPORT_OK экспортирует символы по требованию для выборочного списка символов (подпрограмм и переменных) модуля.

Но я действительно не вижу здесь разницы/значения.
Может ли кто-нибудь дать небольшой фундаментальный пример различия/использования этих двух символов?

4b9b3361

Ответ 1

Скажем, у меня есть пакет MyPackage, который использует @EXPORT.

#this is MyPackage.pm
package MyPackage;
@EXPORT = qw(do_awesome_thing);

sub do_awesome_thing { ... }

sub be_awesome { ... }

Теперь, когда я использую MyPackage в своем коде,

#this is myscript.pl
use MyPackage;

do_awesome_thing(); #works

be_awesome(); #doesn't work
MyPackage::be_awesome(); #works

do_awesome_thing автоматически экспортируется в мой код из MyPackage, без необходимости говорить "дайте мне это". be_awesome не экспортируется (и он не будет экспортироваться с помощью @EXPORT_OK), я просто покажу эту часть, чтобы вы поняли, что дает нам "экспорт" ).

С другой стороны, если у меня есть пакет MyOtherPackage, который использует @EXPORT_OK,

#this is MyOtherPackage.pm
package MyOtherPackage;
@EXPORT_OK = qw(do_awesome_thing);

sub do_awesome_thing { ... }

sub be_awesome { ... }

а затем попробуйте

#this is mynewscript.pl
use MyOtherPackage;

do_awesome_thing(); #doesn't work
MyOtherPackage::do_awesome_thing(); #works, as always

прямая вызов do_awesome_thing напрямую не будет работать. Это связано с тем, что помещение чего-то в @EXPORT_OK говорит "дайте это моим пользователям, только если они попросят об этом". Поскольку мы только что сказали use MyOtherPackage без явного запроса на do_awesome_thing для импорта здесь, он не импортируется и доступен только путем указания имени пакета.

Способ импорта do_awesome_thing, который вы хотите импортировать, состоит в том, чтобы сказать use MyOtherPackage qw(do_awesome_thing) во второй строке mynewscript.pl выше. Это говорит о том, что импортировать этот модуль и сделать do_awesome_thing доступным напрямую. После этого начнет работать четвертая строка в mynewscript.pl выше.

Обратите внимание, что пользователь может также указать use MyPackage qw(do_awesome_thing) с первым пакетом, и в этом случае ничего другого в списке @EXPORT не будет экспортировано, будет только do_awesome_thing. Таким образом, за исключением случая по умолчанию use PackageName;, @EXPORT и @EXPORT_OK ведут себя аналогичным образом. В случае по умолчанию все в @EXPORT автоматически загружается в пользователя script, а @EXPORT_OK более вежлив и ничего не экспортирует.

Ответ 2

Из руководства fine Exporter:

  • use YourModule;
    Это импортирует все символы из MyModule @EXPORT в пространство имен оператора use.
  • use YourModule ();
    Это приводит к тому, что perl загружает ваш модуль, но не импортирует никаких символов.
  • use YourModule qw(...);
    Это импортирует только символы, перечисленные вызывающим в их пространство имен. Все перечисленные символы должны быть в @EXPORT или @EXPORT_OK, иначе возникает ошибка. Доступны расширенные функции экспорта Exporter, но с элементами списка, которые синтаксически отличаются от имен символов.

Итак, если вы используете @EXPORT, а кто-то делает обычный use YourModule;, то вы просто загрязнили их пространство имен всем, что находится в @EXPORT. Но если вы используете @EXPORT_OK, им необходимо специально спросить, что вещи будут импортированы, чтобы человек, использующий ваш модуль, контролировал, что происходит с их пространством имен.

Разница заключается в том, кто контролирует то, что попадает в пространство имен use r: если вы используете @EXPORT, тогда модуль use d, если вы используете @EXPORT_OK, тогда код, делающий импорт контролирует собственное пространство имен.

Конечно, вы всегда можете сказать use Whatever();, чтобы неловкие модули загрязняли ваше пространство имен, но это некрасиво, и вам не нужно будет клониться вокруг грубого кода, который хочет писать все пространство вашего пространства имен.