perlfaq7
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ВЕРСИЯ
- ОПИСАНИЕ
- Можно ли получить BNF/yacc/RE для языка Perl?
- Какие это все знаки препинания $@%&* и как я узнаю, когда их использовать?
- Всегда ли/никогда не нужно указывать в кавычках мои строки или использовать точки с запятой и запятые?
- Как пропустить некоторые возвращаемые значения?
- Как временно заблокировать предупреждения?
- Что такое расширение?
- Почему операторы Perl имеют разный приоритет, чем операторы C?
- Как объявить/создать структуру?
- Как создать модуль?
- Как принять или захватить модуль, уже находящийся на CPAN?
- Как создать класс?
- Как я могу определить, является ли переменная заражённой?
- Что такое замыкание?
- Что такое самоубийство переменных и как его предотвратить?
- Как передать/вернуть {Функция, дескриптор файла, массив, хеш, метод, регулярное выражение}?
- Как создать статическую переменную?
- В чем разница между динамическим и лексическим (статическим) охватом? Между local() и my()?
- Как я могу получить доступ к динамической переменной, пока аналогичная лексическая находится в области видимости?
- В чем разница между глубокой и мелкой привязкой?
- Почему "my($foo) = <$fh>;" не работает правильно?
- Как переопределить встроенную функцию, оператор или метод?
- В чем разница между вызовом функции как &foo и foo()?
- Как создать оператор switch или case?
- Как перехватить обращения к неопределенным переменным, функциям или методам?
- Почему метод, включенный в этот же файл, не найден?
- Как узнать мой текущий или вызывающий пакет?
- Как прокомментировать большой блок кода Perl?
- Как очистить пакет?
- Как использовать переменную в качестве имени переменной?
- Что означает "плохой интерпретатор"?
- Нужно ли перекомпилировать XS-модули при изменении библиотеки C?
- АВТОР И АВТОРСКИЕ ПРАВА
НАЗВАНИЕ
perlfaq7 - Общие вопросы по языку Perl
ВЕРСИЯ
версия 5.20210520
ОПИСАНИЕ
Этот раздел посвящен общим проблемам языка Perl, которые не явно относятся к другим разделам.
Можно ли получить BNF/yacc/RE для языка Perl?
BNF нет, но вы можете попытаться разобраться с грамматикой yacc в perly.y в дистрибутиве исходных кодов, если вы достаточно смелы. Грамматика опирается на очень умный код токенизации, поэтому приготовьтесь углубиться и в toke.c тоже.
Словами Хаима Френкеля: «Грамматику Perl нельзя свести к BNF. Работа по разбору perl распределена между yacc, лексером, дымом и зеркалами».
Какие это все знаки препинания $@%&* и как я узнаю, когда их использовать?
Это спецификаторы типов, как подробно описано в perldata:
$ for scalar values (number, string or reference)
@ for arrays
% for hashes (associative arrays)
& for subroutines (aka functions, procedures, methods)
* for all types of that symbol name. In version 4 you used them like
pointers, but in modern perls you can just use references. Есть несколько других символов, с которыми вы, вероятно, столкнетесь, которые не являются спецификаторами типов:
<> are used for inputting a record from a filehandle.
\ takes a reference to something. Обратите внимание, что <FILE> не является спецификатором типа для файлов, ни именем дескриптора. Это <> оператор, примененный к дескриптору FILE. Он читает одну строку (ну, запись—см. "$/" в perlvar) из дескриптора FILE в скалярном контексте или все строки в списочном контексте. При выполнении открывания, закрытия или любой другой операции, кроме <> с файлами, или даже при разговоре о дескрипторе, не используйте скобки. Правильно: eof(FH), seek(FH, 0, 2) и «копирование из STDIN в FILE».
Всегда ли/никогда не нужно указывать в кавычках мои строки или использовать точки с запятой и запятые?
Обычно, голые слова не нуждаются в кавычках, но в большинстве случаев, вероятно, стоит их использовать (и это необходимо в use strict). Но ключевое слово хеша, состоящее из простого слова, и левосторонний операнд к => оператору оба считаются такими, как будто они были в кавычках:
This is like this
------------ ---------------
$foo{line} $foo{'line'}
bar => stuff 'bar' => stuff Последняя точка с запятой в блоке необязательна, как и последняя запятая в списке. Хороший стиль (см. perlstyle) предлагает их использовать, кроме однострочных:
if ($whoops) { exit 1 }
my @nums = (1, 2, 3);
if ($whoops) {
exit 1;
}
my @lines = (
"There Beren came from mountains cold",
"And lost he wandered under leaves",
); Как пропустить некоторые возвращаемые значения?
Один из способов — обработать возвращаемые значения как список и обратиться к ним по индексу:
$dir = (getpwnam($user))[7]; Другой способ — использовать undef в качестве элемента слева:
($dev, $ino, undef, undef, $uid, $gid) = stat($file); Также можно использовать срез списка, чтобы выбрать только нужные элементы:
($dev, $ino, $uid, $gid) = ( stat($file) )[0,1,4,5]; Как временно заблокировать предупреждения?
Если вы используете Perl 5.6.0 или более позднюю версию, use warnings pragma позволяет тонко управлять создаваемыми предупреждениями. См. perllexwarn для получения дополнительных сведений.
{
no warnings; # temporarily turn off warnings
$x = $y + $z; # I know these might be undef
} Кроме того, вы можете включить и выключить категории предупреждений. Отключите те категории, которые хотите игнорировать, и при этом вы всё ещё будете получать другие категории предупреждений. Смотрите perllexwarn для получения всех деталей, включая имена категорий и иерархию.
{
no warnings 'uninitialized';
$x = $y + $z;
} Если у вас более старая версия Perl, переменная $^W (описанная в perlvar) управляет предупреждениями во время выполнения для блока:
{
local $^W = 0; # temporarily turn off warnings
$x = $y + $z; # I know these might be undef
} Обратите внимание, что, как и все переменные знаков препинания, вы не можете использовать my() с $^W, только local().
Что такое расширение?
Расширение — это способ вызова скомпилированного кода C из Perl. Чтение perlxstut — хорошее место для получения дополнительной информации об расширениях.
Почему операторы Perl имеют разный приоритет, чем операторы C?
На самом деле, нет. Все операторы C, которые Perl копирует, имеют тот же приоритет в Perl, что и в C. Проблема в операторах, которых нет в C, особенно функциях, которые дают списочный контекст всему справа, например, print, chmod, exec и так далее. Такие функции называются «операторами списка» и как таковые появляются в таблице приоритетов в perlop.
Распространённая ошибка: написать:
unlink $file || die "snafu"; Это интерпретируется как:
unlink ($file || die "snafu"); Чтобы избежать этой проблемы, либо добавьте дополнительные скобки, либо используйте оператор or с очень низким приоритетом:
(unlink $file) || die "snafu";
unlink $file or die "snafu"; Операторы «English» (and, or, xor, и not) намеренно имеют приоритет ниже, чем операторы списка, именно для таких ситуаций, как та, что описана выше.
Ещё один оператор со сюрпризами в приоритете — возведение в степень. Он связывает сильнее, даже чем унарный минус, заставляя -2**2 давать отрицательное четыре, а не положительное одно. Он также правоассоциативен, то есть 2**3**2 — это два в девятой степени, а не восемь в квадрате.
Хотя он имеет тот же приоритет, что и в C, оператор Perl ?: производит lvalue. Это присваивает $x либо $if_true, либо $if_false, в зависимости от истинности $maybe:
($maybe ? $if_true : $if_false) = $x; Как объявить/создать структуру?
В общем случае, вы не «объявляете» структуру. Просто используйте (вероятно, анонимную) ссылку на хеш. Смотрите perlref и perldsc для получения подробностей. Вот пример:
$person = {}; # new anonymous hash
$person->{AGE} = 24; # set field AGE to 24
$person->{NAME} = "Nat"; # set field NAME to "Nat" Если вам нужно что-то более строгое, попробуйте perlootut.
Как создать модуль?
perlnewmod — хорошая отправная точка, игнорируйте части об загрузке на CPAN, если вы не хотите сделать ваш модуль общедоступным.
ExtUtils::ModuleMaker и Module::Starter — тоже хорошие стартовые точки. Многие авторы из CPAN теперь используют Dist::Zilla для автоматизации максимально возможного.
Подробная документация о модулях находится в: perlmod, perlmodlib, perlmodstyle.
Если вам нужно включить код C или интерфейсы библиотек C, используйте h2xs. h2xs создаст структуру модуля и начальные файлы интерфейса. perlxs и perlxstut объясняют подробности.
Как принять или перенять модуль, уже имеющийся на CPAN?
Попросите текущего администратора сделать вас со-администратором или передать вам модуль.
Если по какой-то причине вы не можете связаться с автором, обратитесь к администраторам PAUSE по адресу modules@perl.org, которые могут помочь, но каждый случай рассматривается индивидуально.
-
Получите учетную запись для Perl Authors Upload Server (PAUSE), если у вас её еще нет: http://pause.perl.org
-
Напишите на modules@perl.org, объяснив, что вы предприняли для связи с текущим администратором. Администраторы PAUSE также попытаются связаться с администратором.
-
Опубликуйте сообщение в популярном сообществе, объявив о своем намерении перенять модуль.
-
Подождите немного. Администраторы PAUSE не хотят действовать слишком быстро, если текущий администратор в отпуске. Если на частное сообщение или публичное сообщение нет ответа, администратор PAUSE может передать модуль вам.
Как создать класс?
(предложено brian d foy)
В Perl, класс — это просто пакет, а методы — это просто подпрограммы. Perl не усложняет это и позволяет настраивать пакет так, как вам нравится (то есть, ничего не настраивает за вас).
См. также perlootut, учебник, охватывающий создание классов, и perlobj.
Как узнать, если переменная заражена?
Вы можете использовать функцию tainted() модуля Scalar::Util, доступного из CPAN (или включенного в Perl начиная с версии 5.8.0). См. также "Стирка и обнаружение заражённых данных" в perlsec.
Что такое замыкание?
Замыкания документированы в perlref.
Замыкание — это термин компьютерных наук с точным, но труднообъяснимым значением. Обычно в Perl замыкания реализуются как анонимные подпрограммы с постоянными ссылками на лексические переменные вне собственного диапазона видимости. Эти лексические переменные волшебным образом ссылаются на переменные, существовавшие во время определения подпрограммы (глубокая привязка).
Замыкания чаще всего используются в языках программирования, где возвращаемое значение функции может быть само по себе функцией, как это возможно в Perl. Обратите внимание, что некоторые языки предоставляют анонимные функции, но не способны обеспечить надлежащие замыкания: например, язык Python. Для получения дополнительной информации о замыканиях ознакомьтесь с любой книгой по функциональному программированию. Язык Scheme не только поддерживает, но и поощряет замыкания.
Вот классическая функция генерации функций без замыкания:
sub add_function_generator {
return sub { shift() + shift() };
}
my $add_sub = add_function_generator();
my $sum = $add_sub->(4,5); # $sum is 9 now. Анонимная подпрограмма, возвращаемая add_function_generator(), технически не является замыканием, поскольку она не ссылается на лексические переменные вне своего собственного диапазона видимости. Использование замыкания даёт вам шаблон функции с некоторыми незаполненными слотами для последующей настройки.
В отличие от следующей функции make_adder(), в которой возвращаемая анонимная функция содержит ссылку на лексическую переменную за пределами области видимости этой функции. Такая ссылка требует, чтобы Perl возвратил правильное замыкание, таким образом фиксируя навсегда значение, которое имела лексическая переменная при создании функции.
sub make_adder {
my $addpiece = shift;
return sub { shift() + $addpiece };
}
my $f1 = make_adder(20);
my $f2 = make_adder(555); Теперь $f1->($n) всегда равно 20 плюс любое значение $n, которое вы передаете, тогда как $f2->($n) всегда равно 555 плюс любое значение $n, которое вы передаете. $addpiece в замыкании сохраняется.
Замыкания часто используются для менее экзотических целей. Например, когда вы хотите передать фрагмент кода в функцию:
my $line;
timeout( 30, sub { $line = <STDIN> } ); Если бы код для выполнения был передан в виде строки, '$line = <STDIN>', у гипотетической функции timeout() не было бы способа получить доступ к лексической переменной $line в области видимости вызывающего её кода.
Ещё одно применение замыкания — сделать переменную приватной для именованной подпрограммы, например, счётчик, который инициализируется во время создания подпрограммы и может быть изменён только изнутри подпрограммы. Это иногда используется с блоком BEGIN в файлах пакетов, чтобы убедиться, что переменная не изменяется в течение всего жизненного цикла пакета:
BEGIN {
my $id = 0;
sub next_id { ++$id }
} Это обсуждается более подробно в perlsub; см. раздел Постоянные приватные переменные.
Что такое самоубийство переменной и как его предотвратить?
Эта проблема была решена в perl 5.004_05, поэтому её предотвращение означает обновление вашей версии perl. ;)
Самоубийство переменной — это когда вы (временнно или постоянно) теряете значение переменной. Это происходит из-за применения my() и local() в сочетании с замыканиями или алиасированными переменными итератора foreach() и аргументами подпрограмм. Раньше было легко случайно потерять значение переменной таким образом, но сейчас это намного сложнее. Рассмотрим этот код:
my $f = 'foo';
sub T {
while ($i++ < 3) { my $f = $f; $f .= "bar"; print $f, "\n" }
}
T;
print "Finally $f\n"; Если вы столкнулись с самоубийством переменной, то my $f в подпрограмме не получает свежую копию $f, значение которой равно 'foo'. Вывод показывает, что внутри подпрограммы значение $f просачивается, когда этого не должно быть, как в этом выводе:
foobar
foobarbar
foobarbarbar
Finally foo Переменная $f, к которой трижды добавляется "bar", должна быть новой $f my $f должны создавать новую лексическую переменную на каждом проходе цикла. Ожидаемый вывод:
foobar
foobar
foobar
Finally foo Как передать/вернуть {Функцию, дескриптор файла, массив, хеш, метод, регулярное выражение}?
Вам нужно передать ссылки на эти объекты. См. "Передача по ссылке" в perlsub по этому вопросу и perlref для информации о ссылках.
- Передача переменных и функций
-
Обычные переменные и функции довольно легко передавать: просто передайте ссылку на существующую или анонимную переменную или функцию:
func( \$some_scalar ); func( \@some_array ); func( [ 1 .. 10 ] ); func( \%some_hash ); func( { this => 10, that => 20 } ); func( \&some_func ); func( sub { $_[0] ** $_[1] } ); - Передача дескрипторов файлов
-
Начиная с Perl 5.6, дескрипторы файлов можно представлять скалярными переменными, которые обрабатываются как любые другие скаляры.
open my $fh, $filename or die "Cannot open $filename! $!"; func( $fh ); sub func { my $passed_fh = shift; my $line = <$passed_fh>; }До Perl 5.6, вам приходилось использовать обозначения
*FHили\*FH. Это "типглобы" — см. "Типглобы и дескрипторы файлов" в perldata и особенно "Передача по ссылке" в perlsub для получения дополнительной информации. - Передача регулярных выражений
-
Вот пример того, как передать строку и регулярное выражение для сопоставления с ней. Вы создаёте шаблон с помощью оператора
qr//.sub compare { my ($val1, $regex) = @_; my $retval = $val1 =~ /$regex/; return $retval; } $match = compare("old McDonald", qr/d.*D/i); - Передача методов
-
Чтобы передать метод объекта в подпрограмму, вы можете сделать это:
call_a_lot(10, $some_obj, "methname") sub call_a_lot { my ($count, $widget, $trick) = @_; for (my $i = 0; $i < $count; $i++) { $widget->$trick(); } }Или вы можете использовать замыкание, чтобы объединить объект, вызов его метода и аргументы:
my $whatnot = sub { $some_obj->obfuscate(@args) }; func($whatnot); sub func { my $code = shift; &$code(); }Вы также можете исследовать метод can() в классе UNIVERSAL (часть стандартного распределения Perl).
Как создать статическую переменную?
(предложено brian d foy)
В Perl 5.10 объявите переменную с state. Объявление state создаёт лексическую переменную, которая сохраняется между вызовами подпрограммы:
sub counter { state $count = 1; $count++ } Вы можете имитировать статическую переменную, используя лексическую переменную, которая выходит из области видимости. В этом примере вы определяете подпрограмму counter, и она использует лексическую переменную $count. Поскольку вы заключаете это в блок BEGIN, $count определена во время компиляции, но также выходит из области видимости в конце блока BEGIN. Блок BEGIN также гарантирует, что подпрограмма и используемое ею значение определены во время компиляции, так что подпрограмма готова к использованию, как и любая другая подпрограмма, и вы можете поместить этот код в то же место, что и другие подпрограммы в тексте программы (т.е. в конце кода, как правило). Подпрограмма counter всё ещё ссылается на данные, и это единственный способ получить доступ к значению (и каждый раз вы увеличиваете значение). Данные в куске памяти, определённом $count, приватны для counter.
BEGIN {
my $count = 1;
sub counter { $count++ }
}
my $start = counter();
.... # code that calls counter();
my $end = counter(); В предыдущем примере вы создали переменную, приватную для функции, потому что только одна функция сохраняла на неё ссылку. Вы можете определить несколько функций, в то время как переменная находится в области видимости, и каждая функция может использовать "приватную" переменную. Это не совсем "статическое", потому что к ней можно получить доступ вне функции, пока лексическая переменная находится в области видимости, и даже создать ссылки на неё. В этом примере increment_count и return_count используют общую переменную. Одна функция добавляет к значению, а другая просто возвращает значение. Они оба могут получить доступ к $count, и поскольку она вышла из области видимости, нет другого способа получить к ней доступ.
BEGIN {
my $count = 1;
sub increment_count { $count++ }
sub return_count { $count }
} Для объявления переменной, приватной для файла, вы по-прежнему используете лексическую переменную. Файл также является областью видимости, поэтому лексическую переменную, определённую в файле, нельзя увидеть из другого файла.
См. "Постоянные приватные переменные" в perlsub для получения дополнительной информации. Обсуждение замыканий в perlref может помочь, даже если в этом ответе не использовались анонимные подпрограммы. См. "Постоянные приватные переменные" в perlsub для подробностей.
В чём разница между динамическим и лексическим (статическим) охватом? Между local() и my()?
local($x) сохраняет старое значение глобальной переменной $x и присваивает новое значение на время выполнения подпрограммы которое видно в других функциях, вызываемых из этой подпрограммы. Это делается во время выполнения, поэтому называется динамическим охватом. local() всегда влияет на глобальные переменные, также называемые пакетом переменных или динамическими переменными.
my($x) создаёт новую переменную, видимую только в текущей подпрограмме. Это выполняется во время компиляции, поэтому называется лексическим или статическим охватом. my() всегда влияет на приватные переменные, также называемые лексическими переменными или (неправильно) статическими переменными.
Например:
sub visible {
print "var has value $var\n";
}
sub dynamic {
local $var = 'local'; # new temporary value for the still-global
visible(); # variable called $var
}
sub lexical {
my $var = 'private'; # new private variable, $var
visible(); # (invisible outside of sub scope)
}
$var = 'global';
visible(); # prints global
dynamic(); # prints local
lexical(); # prints global Обратите внимание, что нигде не выводится значение "приватное". Это потому, что $var имеет это значение только внутри блока функции lexical(), и оно скрыто от вызываемой подпрограммы.
Вкратце, local() не делает то, что вы считаете приватными локальными переменными. Она даёт глобальной переменной временное значение. my() — это то, что вам нужно, если вы хотите приватные переменные.
См. "Приватные переменные с помощью my()" в perlsub и "Временные значения с помощью local()" в perlsub для подробных разъяснений.
Как получить доступ к динамической переменной, пока аналогично названная лексическая переменная находится в области видимости?
Если вам известен ваш пакет, вы можете просто упомянуть его явно, как в $Some_Pack::var. Обратите внимание, что обозначение $::var не является динамической переменной $var в текущем пакете, а скорее переменной в пакете «main», как будто вы написали $main::var.
use vars '$var';
local $var = "global";
my $var = "lexical";
print "lexical is $var\n";
print "global is $main::var\n"; В качестве альтернативы вы можете использовать директиву компилятора our(), чтобы добавить динамическую переменную в текущую лексическую область видимости.
require 5.006; # our() did not exist before 5.6
use vars '$var';
local $var = "global";
my $var = "lexical";
print "lexical is $var\n";
{
our $var;
print "global is $var\n";
} Разница между глубокой и мелкой привязкой?
При глубокой привязке лексические переменные, упомянутые в анонимных подпрограммах, — это те же переменные, которые находились в области видимости при создании подпрограммы. При мелкой привязке — это те переменные с такими же именами, которые находятся в области видимости при вызове подпрограммы. Perl всегда использует глубокую привязку лексических переменных (т. е. переменных, созданных с помощью my()). Однако динамические переменные (также известные как глобальные, локальные или переменные пакета) фактически привязаны мелко. Подумайте об этом как о еще одной причине, чтобы не использовать их. См. ответ на «Что такое замыкание?».
Почему «my($foo) = <$fh>;» работает неправильно?
my() и local() задают контекст списка для правой части =. Операция чтения <$fh>, как и многие функции и операторы Perl, может определить контекст, в котором она была вызвана, и вести себя соответствующим образом. В общем случае функция scalar() может помочь. Эта функция ничего не делает с данными самими по себе (вопреки распространенному мифу), а скорее говорит своему аргументу вести себя соответствующим образом в скалярном контексте. Если у этой функции нет определенного скалярного поведения, это, конечно, не поможет (например, с sort()).
Для принудительного скалярного контекста в этом конкретном случае достаточно опустить скобки:
local($foo) = <$fh>; # WRONG
local($foo) = scalar(<$fh>); # ok
local $foo = <$fh>; # right Вы, вероятно, все равно должны использовать лексические переменные, хотя проблема остается той же:
my($foo) = <$fh>; # WRONG
my $foo = <$fh>; # right Как переопределить встроенную функцию, оператор или метод?
Зачем вам это нужно? :-)
Если вы хотите переопределить предопределенную функцию, такую как open(), то вам нужно будет импортировать новое определение из другого модуля. См. "Переопределение встроенных функций" в perlsub.
Если вы хотите перегрузить оператор Perl, такой как + или **, то вам понадобится использовать pragma use overload, документированный в overload.
Если вы говорите о скрытии вызовов методов в родительских классах, см. "Переопределение методов и разрешение методов" в perlootut.
В чем разница между вызовом функции как &foo и foo()?
(предложено brian d foy)
Вызов подпрограммы как &foo без заключительных скобок игнорирует прототип foo и передает ей текущее значение списка аргументов @_. Вот пример; подпрограмма bar вызывает подпрограмму &foo, которая выводит список ее аргументов:
sub foo { print "Args in foo are: @_\n"; }
sub bar { &foo; }
bar( "a", "b", "c" ); При вызове bar с аргументами вы видите, что foo получила тот же @_.
Args in foo are: a b c Вызов подпрограммы с заключительными скобками, с аргументами или без, не использует текущий @_. Изменение примера, чтобы добавить скобки после вызова foo, изменяет программу:
sub foo { print "Args in foo are: @_\n"; }
sub bar { &foo(); }
bar( "a", "b", "c" ); Теперь вывод показывает, что foo не получает @_ от своего вызывающего объекта.
Args in foo are: Однако, использование & в вызове по-прежнему переопределяет прототип foo если он присутствует:
sub foo ($$$) { print "Args infoo are: @_\n"; }
sub bar_1 { &foo; }
sub bar_2 { &foo(); }
sub bar_3 { foo( $_[0], $_[1], $_[2] ); }
# sub bar_4 { foo(); }
# bar_4 doesn't compile: "Not enough arguments for main::foo at ..."
bar_1( "a", "b", "c" );
# Args in foo are: a b c
bar_2( "a", "b", "c" );
# Args in foo are:
bar_3( "a", "b", "c" );
# Args in foo are: a b c Основное использование функции прохождения @_ заключается в написании подпрограмм, основная задача которых — вызывать для вас другие подпрограммы. Для получения дополнительной информации см. perlsub.
Как создать оператор switch или case?
В Perl есть оператор given/when, но он экспериментальный и, вероятно, изменится в будущем. Подробнее см. perlsyn.
В общем случае, используйте модуль CPAN, например, Switch::Plain:
use Switch::Plain;
sswitch($variable_holding_a_string) {
case 'first': { }
case 'second': { }
default: { }
} или для более сложных сравнений, if-elsif-else:
for ($variable_to_test) {
if (/pat1/) { } # do something
elsif (/pat2/) { } # do something else
elsif (/pat3/) { } # do something else
else { } # default
} Вот простой пример оператора switch, основанного на сопоставлении с образцом, выстроенного таким образом, чтобы он выглядел как оператор switch. Мы выполним многопутевое условное выражение, основанное на типе ссылки, хранящейся в $whatchamacallit:
SWITCH: for (ref $whatchamacallit) {
/^$/ && die "not a reference";
/SCALAR/ && do {
print_scalar($$ref);
last SWITCH;
};
/ARRAY/ && do {
print_array(@$ref);
last SWITCH;
};
/HASH/ && do {
print_hash(%$ref);
last SWITCH;
};
/CODE/ && do {
warn "can't print function ref";
last SWITCH;
};
# DEFAULT
warn "User defined type skipped";
} См. perlsyn для других примеров в этом стиле.
Иногда вам следует изменить позиции константы и переменной. Например, скажем, вы хотите проверить, какой из нескольких ответов вам был дан, но в регистронезависимом стиле, также разрешая сокращения. Вы можете использовать следующую технику, если строки все начинаются с разных символов или если вы хотите упорядочить совпадения так, чтобы одно имело приоритет перед другим, как "SEND" имеет приоритет перед "STOP" здесь:
chomp($answer = <>);
if ("SEND" =~ /^\Q$answer/i) { print "Action is send\n" }
elsif ("STOP" =~ /^\Q$answer/i) { print "Action is stop\n" }
elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" }
elsif ("LIST" =~ /^\Q$answer/i) { print "Action is list\n" }
elsif ("EDIT" =~ /^\Q$answer/i) { print "Action is edit\n" } Полностью другой подход заключается в создании хэша ссылок на функции.
my %commands = (
"happy" => \&joy,
"sad", => \&sullen,
"done" => sub { die "See ya!" },
"mad" => \&angry,
);
print "How are you? ";
chomp($string = <STDIN>);
if ($commands{$string}) {
$commands{$string}->();
} else {
print "No such command: $string\n";
} Начиная с Perl 5.8, можно использовать модуль фильтра исходного кода Switch, чтобы получить switch и case. Его использование сейчас не рекомендуется, потому что он не полностью совместим с родным switch Perl 5.10 и потому что, как реализованный фильтр исходного кода, он не всегда работает так, как ожидается, когда задействована сложная синтаксическая структура.
Как перехватить обращения к неопределенным переменным, функциям или методам?
Метод AUTOLOAD, описанный в "Автозагрузка" в perlsub, позволяет перехватывать вызовы неопределенных функций и методов.
Когда дело доходит до неопределенных переменных, которые вызовут предупреждение в use warnings, вы можете преобразовать предупреждение в ошибку.
use warnings FATAL => qw(uninitialized); Почему не найден метод, включенный в тот же файл?
Возможные причины: путаница с наследованием, неверно введено имя метода или объект неверного типа. Подробнее о каждом из этих случаев см. perlootut. Вы также можете использовать print ref($object) для выяснения класса, в который был освящен $object.
Еще одна возможная причина проблем — использование синтаксиса косвенного объекта (например, find Guru "Samy") для имени класса до того, как Perl обнаружит существование такого пакета. Лучше всего убедиться, что все ваши пакеты определены, прежде чем начать их использовать, что будет учтено при использовании инструкции use вместо require. В противном случае убедитесь, что вы используете стрелочный синтаксис (например, Guru->find("Samy")) вместо него. Синтаксис объекта описан в perlobj.
Убедитесь, что вы прочли информацию о создании модулей в perlmod и о опасностях косвенных объектов в "Вызов метода" в perlobj.
Как узнать свой текущий или вызывающий пакет?
(предложено brian d foy)
Чтобы узнать пакет, в котором вы сейчас находитесь, используйте специальную литеральную запись __PACKAGE__, как описано в perldata. Вы можете использовать специальные литеральные записи только как отдельные токены, поэтому вы не можете интерполировать их в строки так же, как вы можете с переменными:
my $current_package = __PACKAGE__;
print "I am in package $current_package\n"; Если вам нужно узнать пакет, вызывающий ваш код, возможно, для предоставления лучшей диагностики, как это делает Carp, используйте встроенную функцию caller:
sub foo {
my @args = ...;
my( $package, $filename, $line ) = caller;
print "I was called from package $package\n";
); По умолчанию ваша программа запускается в пакете main, поэтому вы всегда находитесь в каком-то пакете.
Это отличается от определения пакета, в который освящен объект, который может не совпадать с текущим пакетом. Для этого используйте blessed из Scalar::Util, являющегося частью стандартной библиотеки с Perl 5.8:
use Scalar::Util qw(blessed);
my $object_package = blessed( $object ); Большую часть времени вам не должно быть важно, в какой пакет освящен объект, если только он не утверждает, что наследует от этого класса:
my $is_right_class = eval { $object->isa( $package ) }; # true or false И с Perl 5.10 и более поздними версиями вам не нужно проверять наследование, чтобы увидеть, может ли объект обработать роль. Для этого вы можете использовать DOES, который из UNIVERSAL:
my $class_does_it = eval { $object->DOES( $role ) }; # true or false Вы можете безопасно заменить isa на DOES (хотя обратное неверно).
Как закомментировать большой блок кода Perl?
(предложено brian d foy)
Быстрый и грязный способ закомментировать более одной строки Perl — это заключить эти строки в директивы Pod. Эти директивы должны стоять в начале строки и в месте, где Perl ожидает новую инструкцию (следовательно, не посредине инструкций, например, в комментариях #). Комментарий завершается =cut, завершая раздел Pod:
=pod
my $object = NotGonnaHappen->new();
ignored_sub();
$wont_be_assigned = 37;
=cut Быстрый и грязный метод работает хорошо, только если вы не планируете оставлять закомментированный код в исходном коде. Если появится анализатор Pod, ваш многострочный комментарий появится в переводе Pod. Лучший способ скрывает его и от анализаторов Pod.
Директива =begin может пометить раздел для определенной цели. Если анализатор Pod не хочет обрабатывать его, он просто игнорирует его. Ознакомьтесь с комментариями, помеченными comment. Комментарий завершается с помощью =end с тем же меткой. Вам по-прежнему необходима =cut, чтобы вернуться к коду Perl из комментария Pod:
=begin comment
my $object = NotGonnaHappen->new();
ignored_sub();
$wont_be_assigned = 37;
=end comment
=cut Для получения дополнительной информации о Pod, ознакомьтесь с perlpod и perlpodspec.
Как очистить пакет?
Используйте этот код, предоставленный Марком-Джейсоном Доминусом:
sub scrub_package {
no strict 'refs';
my $pack = shift;
die "Shouldn't delete main package"
if $pack eq "" || $pack eq "main";
my $stash = *{$pack . '::'}{HASH};
my $name;
foreach $name (keys %$stash) {
my $fullname = $pack . '::' . $name;
# Get rid of everything with that name.
undef $$fullname;
undef @$fullname;
undef %$fullname;
undef &$fullname;
undef *$fullname;
}
} Или, если вы используете недавнюю версию Perl, вы можете просто использовать функцию Symbol::delete_package() вместо нее.
Как использовать переменную как имя переменной?
Начинающие часто думают, что хотят иметь переменную, содержащую имя переменной.
$fred = 23;
$varname = "fred";
++$$varname; # $fred now 24 Это работает иногда, но это очень плохая идея по двум причинам.
Первая причина заключается в том, что эта техника работает только с глобальными переменными. Это означает, что если $fred — лексическая переменная, созданная с помощью my() в приведенном выше примере, код вообще не будет работать: вы случайно обратитесь к глобальной переменной и пропустите частную лексическую переменную. Глобальные переменные плохи, поскольку они могут легко случайным образом сталкиваться, и в целом приводят к не масштабируемому и запутанному коду.
Символьные ссылки запрещены под влиянием pragmy use strict. Они не являются истинными ссылками и, следовательно, не учитываются при подсчете ссылок и не собираются сборщиком мусора.
Другая причина, по которой использование переменной для хранения имени другой переменной — плохая идея, заключается в том, что этот вопрос часто возникает из-за непонимания структур данных Perl, особенно хэшей. Используя символьные ссылки, вы просто используете хэш таблицы символов пакета (например, %main::) вместо пользовательского хэша. Решение состоит в использовании собственного хэша или реальной ссылки вместо него.
$USER_VARS{"fred"} = 23;
my $varname = "fred";
$USER_VARS{$varname}++; # not $$varname++ В этом случае используется хеш %USER_VARS вместо символических ссылок. Иногда это возникает при чтении строк от пользователя с переменными ссылками и желании расширить их до значений переменных вашей программы Perl. Это также плохая идея, поскольку она объединяет пространство имен, доступное для программы, и пространство имен, доступное для пользователя. Вместо того, чтобы читать строку и расширять её до фактического содержимого переменных вашей программы:
$str = 'this has a $fred and $barney in it';
$str =~ s/(\$\w+)/$1/eeg; # need double eval лучше сохранить хеш, например, %USER_VARS, и чтобы ссылки на переменные фактически ссылались на записи в этом хеше:
$str =~ s/\$(\w+)/$USER_VARS{$1}/g; # no /e here at all Это быстрее, чище и безопаснее, чем предыдущий подход. Конечно, вам не нужно использовать знак доллара. Вы можете использовать свою собственную схему, чтобы сделать её менее запутанной, например, в квадратных скобках проценты и т. д.
$str = 'this has a %fred% and %barney% in it';
$str =~ s/%(\w+)%/$USER_VARS{$1}/g; # no /e here at all Другая причина, по которой люди иногда думают, что им нужна переменная, содержащая имя переменной, заключается в том, что они не знают, как строить правильные структуры данных, используя хеши. Например, предположим, что они хотели два хеша в своей программе: %fred и %barney, и что они хотели использовать другую скалярную переменную для ссылки на них по имени.
$name = "fred";
$$name{WIFE} = "wilma"; # set %fred
$name = "barney";
$$name{WIFE} = "betty"; # set %barney Это всё ещё символическая ссылка и по-прежнему имеет проблемы, перечисленные выше. Гораздо лучше написать:
$folks{"fred"}{WIFE} = "wilma";
$folks{"barney"}{WIFE} = "betty"; И просто использовать многоуровневый хеш с самого начала.
Единственные случаи, когда вам абсолютно необходимо использовать символические ссылки, — это когда вам действительно необходимо обратиться к таблице символов. Это может быть потому, что к ней нельзя получить реальную ссылку, например, имя формата. Это также может быть важно для вызовов методов, поскольку они всегда проходят через таблицу символов для разрешения.
В этих случаях вы бы отключили strict 'refs' временно, чтобы поэкспериментировать с таблицей символов. Например:
@colors = qw(red blue green yellow orange purple violet);
for my $name (@colors) {
no strict 'refs'; # renege for the block
*$name = sub { "<FONT COLOR='$name'>@_</FONT>" };
} Все эти функции (red(), blue(), green() и т. д.) кажутся отдельными, но фактический код в замыкании на самом деле был скомпилирован только один раз.
Итак, иногда вам может потребоваться использовать символические ссылки для непосредственного управления таблицей символов. Это не имеет значения для форматов, дескрипторов и подпрограмм, потому что они всегда глобальны — вы не можете использовать my() для них. Однако для скаляров, массивов и хешей, а также обычно для подпрограмм, вы, вероятно, захотите использовать жёсткие ссылки.
Что означает сообщение "bad interpreter"?
(внесён Brian D Foy)
Сообщение "bad interpreter" исходит от оболочки, а не от Perl. Фактическое сообщение может меняться в зависимости от вашей платформы, оболочки и настроек локали.
Если вы видите сообщение "bad interpreter - no such file or directory", первая строка в вашем скрипте Perl (строка shebang) не содержит правильного пути к Perl (или любой другой программе, способной запускать скрипты). Иногда это происходит, когда вы перемещаете скрипт с одной машины на другую, и на каждой машине путь к Perl отличается — например, /usr/bin/perl против /usr/local/bin/perl. Это также может указывать на то, что на машине-источнике используются CRLF-разделители строк, а на целевой машине — только LF: оболочка пытается найти /usr/bin/perl
Если вы видите сообщение "bad interpreter: Permission denied", вам нужно сделать ваш скрипт исполняемым.
В любом случае вы по-прежнему сможете запустить скрипты с помощью явного указания perl:
% perl script.pl Если вы получите сообщение «perl: command not found», Perl не находится в вашем PATH, что также может означать, что расположение Perl не соответствует ожиданиям, поэтому вам нужно скорректировать строку shebang.
Нужно ли перекомпилировать модули XS при изменении библиотеки C?
(внесён Alex Beamish)
Если новая версия библиотеки C совместима с ABI (Application Binary Interface) с версией, которую вы обновляете, и если версия разделяемой библиотеки не изменилась, перекомпиляция не потребуется.
АВТОР И АВТОРСКИЕ ПРАВА
Авторские права (c) 1997-2013 Tom Christiansen, Nathan Torkington и другие авторы, как указано. Все права защищены.
Эта документация бесплатна; вы можете распространять и/или изменять её на тех же условиях, что и Perl сам по себе.
Независимо от способа распространения, все примеры кода в этом файле объявляются общественным достоянием. Вам разрешается и рекомендуется использовать этот код в своих программах для развлечения или с выгодой для себя, как вам заблагорассудится. Простой комментарий в коде, приносящий благодарность, был бы вежливым, но не является обязательным.
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/perlfaq7