Скрытые возможности Perl?

Какие действительно полезные, но эзотерические языковые возможности в Perl вы действительно смогли использовать для выполнения полезной работы?

Методические рекомендации:

  • Попробуйте ограничить ответы ядром Perl, а не CPAN
  • Пожалуйста, приведите пример и краткое описание

Скрытые функции также можно найти на других языках. Скрытые функции:

(Это все из ответа Кориона)

  • С
    • Устройство Даффа
    • Портативность и стандартность
  • C#
    • Кавычки для разделенных пробелами списков и строк
    • Псевдонимные пространства имен
  • Джава
    • Статические Инициализаторы
  • JavaScript
    • Функции являются гражданами первого класса
    • Блокировка объема и закрытия
    • Вызов методов и методов доступа косвенно через переменную
  • Рубин
    • Определение методов через код
  • PHP
    • Распространенная онлайн документация
    • Магические методы
    • Символические ссылки
  • питон
    • Обмен значениями одной строки
    • Возможность заменить даже основные функции своими собственными функциями

Другие скрытые возможности:

Операторы:

Цитирование конструкций:

Синтаксис и имена:

Модули, прагмы и параметры командной строки:

Переменные:

Петли и контроль потока:

Регулярные выражения:

Другие преимущества:

Другие приемы и мета-ответы:


Смотрите также:

78 ответов

Оператор триггера полезен для пропуска первой итерации при циклическом просмотре записей (обычно строк), возвращаемых дескриптором файла, без использования переменной flag:

while(<$fh>)
{
  next if 1..1; # skip first record
  ...
}

Бежать perldoc perlop и искать "триггер" для получения дополнительной информации и примеров.

В Perl есть много неочевидных особенностей.

Например, знаете ли вы, что после сигил может быть пробел?

 $ perl -wle 'my $x = 3; print $ x'
 3

Или, что вы можете дать субсимволы числовые имена, если вы используете символические ссылки?

$ perl -lwe '*4 = sub { print "yes" }; 4->()' 
yes

Также есть квазиоператор "bool", который возвращает 1 для истинных выражений и пустую строку для ложных:

$ perl -wle 'print !!4'
1
$ perl -wle 'print !!"0 but true"'
1
$ perl -wle 'print !!0'
(empty line)

Другие интересные вещи: с use overload Вы можете перегрузить строковые литералы и числа (и, например, сделать их BigInts или что-то еще).

Многие из этих вещей фактически где-то документированы или логически вытекают из документированных функций, но, тем не менее, некоторые из них не очень хорошо известны.

Обновление: еще один приятный. Ниже q{...} упоминались конструкции цитирования, но знаете ли вы, что вы можете использовать буквы в качестве разделителей?

$ perl -Mstrict  -wle 'print q bJet another perl hacker.b'
Jet another perl hacker.

Также вы можете писать регулярные выражения:

m xabcx
# same as m/abc/

Добавить поддержку для сжатых файлов с помощью волшебного ARGV:

s{ 
    ^            # make sure to get whole filename
    ( 
      [^'] +     # at least one non-quote
      \.         # extension dot
      (?:        # now either suffix
          gz
        | Z 
       )
    )
    \z           # through the end
}{gzcat '$1' |}xs for @ARGV;

(кавычки около $_ необходимы для обработки имен файлов с метасимволами оболочки в)

Теперь <> функция распакует любой @ARGV файлы, заканчивающиеся на ".gz" или ".Z":

while (<>) {
    print;
}

Одна из моих любимых функций в Perl - использование логического значения || Оператор для выбора между набором вариантов.

 $x = $a || $b;

 # $x = $a, if $a is true.
 # $x = $b, otherwise

Это означает, что можно написать:

 $x = $a || $b || $c || 0;

принять первое истинное значение из $a, $b, а также $c или по умолчанию 0 иначе.

В Perl 5.10 есть также // оператор, который возвращает левую часть, если она определена, и правую часть в противном случае. Следующее выбирает первое определенное значение из $a, $b, $c, или же 0 иначе:

$x = $ a // $ b // $ c // 0;

Они также могут использоваться с их сокращенными формами, которые очень полезны для обеспечения значений по умолчанию:

$x || = 0; # Если $x было ложным, теперь оно имеет значение 0.

$x // = 0; # Если $x был неопределенным, теперь он имеет значение ноль.

Cheerio,

Павел

Операторы ++ и унарные - работают не только с числами, но и со строками.

my $_ = "a"
print -$_

печатает -a

print ++$_

печатает б

$_ = 'z'
print ++$_

печатает аа

Поскольку в Perl есть почти все "эзотерические" части из других списков, я скажу вам одну вещь, которую Perl не может:

Perl не может использовать голые произвольные URL в вашем коде, потому что // Оператор используется для регулярных выражений.

На тот случай, если вам неясно, какие функции предлагает Perl, вот выборочный список, возможно, не совсем очевидных записей:

Устройство Даффа - в Perl

Переносимость и стандартность. Вероятно, с Perl больше компьютеров, чем с компилятором C

Класс манипулирования файлами / путями - File:: Find работает даже в большем количестве операционных систем, чем.Net

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

Псевдонимные пространства имен - в Perl они имеют следующие назначения:

*My::Namespace:: = \%Your::Namespace

Статические инициализаторы - Perl может запускать код практически на каждом этапе компиляции и создания объектов, начиная с BEGIN (разбор кода) для CHECK (после разбора кода) import (при импорте модуля) в new (создание объекта) для DESTROY (уничтожение объекта) до END (программа выхода)

Функции являются гражданами первого класса - как в Perl

Область действия и закрытие блока - в Perl есть

Вызов методов и методов доступа косвенно через переменную - это делает Perl:

my $method = 'foo';
my $obj = My::Class->new();
$obj->$method( 'baz' ); # calls $obj->foo( 'baz' )

Определение методов с помощью кода - Perl это тоже позволяет:

*foo = sub { print "Hello world" };

Распространенная онлайн-документация - Perl-документация находится в сети и, вероятно, в вашей системе тоже

Магические методы, которые вызываются при вызове "несуществующей" функции - Perl реализует это в функции AUTOLOAD

Символические ссылки - вам настоятельно рекомендуется держаться подальше от них. Они будут есть твоих детей. Но, конечно же, Perl позволяет предлагать своих детей кровожадным демонам.

Обмен значениями на одну строку - Perl позволяет присваивать списки

Возможность заменить даже основные функции своими собственными функциями

use subs 'unlink'; 
sub unlink { print 'No.' }

или же

BEGIN{
    *CORE::GLOBAL::unlink = sub {print 'no'}
};

unlink($_) for @ARGV

Автовивификация. AFAIK ни на одном другом языке его нет.

Проще всего процитировать практически любую странную строку в Perl.

my $url = q{http://my.url.com/any/arbitrary/path/in/the/url.html};

На самом деле, различные механизмы цитирования в Perl довольно интересны. Механизмы цитирования в стиле регулярных выражений Perl позволяют вам заключать в кавычки все, указав разделители. Вы можете использовать практически любые специальные символы, такие как #, / или открывать / закрывать символы, такие как (), [] или {}. Примеры:

my $var  = q#some string where the pound is the final escape.#;
my $var2 = q{A more pleasant way of escaping.};
my $var3 = q(Others prefer parens as the quote mechanism.);

Механизмы цитирования:

q: буквальная кавычка; единственный символ, который должен быть экранирован, является конечным символом. qq: интерпретируемая цитата; обрабатывает переменные и экранирующие символы. Отлично подходит для строк, которые нужно процитировать:

my $var4 = qq{This "$mechanism" is broken.  Please inform "$user" at "$email" about it.};

qx: работает как qq, но затем выполняет ее как системную команду, а не в интерактивном режиме. Возвращает весь текст, сгенерированный из стандарта out. (Перенаправление, если поддерживается в ОС, также выходит) Также сделано с обратными кавычками (символ `).

my $output  = qx{type "$path"};      # get just the output
my $moreout = qx{type "$path" 2>&1}; # get stuff on stderr too

qr: интерпретирует как qq, но затем компилирует его как регулярное выражение. Работает с различными опциями в регулярном выражении. Теперь вы можете передать регулярное выражение в качестве переменной:

sub MyRegexCheck {
    my ($string, $regex) = @_;
    if ($string)
    {
       return ($string =~ $regex);
    }
    return; # returns 'null' or 'empty' in every context
}

my $regex = qr{http://[\w]\.com/([\w]+/)+};
@results = MyRegexCheck(q{http://myurl.com/subpath1/subpath2/}, $regex);

qw: очень, очень полезный оператор цитаты. Превращает в кавычки набор слов, разделенных пробелами, в список. Отлично подходит для заполнения данных в модульном тесте.


   my @allowed = qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z { });
   my @badwords = qw(WORD1 word2 word3 word4);
   my @numbers = qw(one two three four 5 six seven); # works with numbers too
   my @list = ('string with space', qw(eight nine), "a $var"); # works in other lists
   my $arrayref = [ qw(and it works in arrays too) ]; 

Они великолепно используют их, когда это проясняет ситуацию. Для qx, qq и q я, скорее всего, использую операторы {}. Чаще всего люди, использующие qw, обычно используют оператор (), но иногда вы также видите qw//.

Оператор "for" можно использовать так же, как "with" в Pascal:

for ($item)
{
    s/&‎nbsp;/ /g;
    s/<.*?>/ /g;
    $_ = join(" ", split(" ", $_));
}

Вы можете применить последовательность операций s/// и т. Д. К одной и той же переменной, не повторяя имя переменной.

ПРИМЕЧАНИЕ. В неразрывном пространстве над (& nbsp;) скрыт Unicode, чтобы обойти уценку. Не копируйте, вставьте это:)

Не совсем скрытый, но многие программисты Perl каждый день не знают о CPAN. Это особенно относится к людям, которые не являются программистами на полную ставку или не программируют на Perl.

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

my @lines = <DATA>;
for (@lines) {
    print if /bad/;
}

__DATA__
some good data
some bad data
more good data 
more good data 

Оператор цитаты - одна из моих любимых вещей. Для сравнения:

my @list = ('abc', 'def', 'ghi', 'jkl');

а также

my @list = qw(abc def ghi jkl);

Гораздо меньше шума, легче для глаз. Еще одна очень приятная вещь в Perl, которую очень не хватает при написании SQL, это то, что завершающая запятая допустима:

print 1, 2, 3, ;

Это выглядит странно, но не если вы сделаете отступ в коде другим способом:

print
    results_of_foo(),
    results_of_xyzzy(),
    results_of_quux(),
    ;

Добавление дополнительного аргумента к вызову функции не требует от вас возиться с запятыми в предыдущих или конечных строках. Изменение одной строки не влияет на окружающие линии.

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

Двоичный "х" является оператором повторения:

print '-' x 80;     # print row of dashes

Также работает со списками:

print for (1, 4, 9) x 3; # print 149149149

Проверка порчи. При включенной проверке заражения Perl умрет (или предупредит -t) если вы попытаетесь передать испорченные данные (грубо говоря, данные извне программы) небезопасной функции (открытие файла, выполнение внешней команды и т. д.). Это очень полезно при написании сценариев setuid или CGI, или чего-либо еще, где сценарий обладает большими привилегиями, чем тот, кто передает ему данные.

Волшебный гото. goto &sub делает оптимизированный хвостовой вызов.

Отладчик

use strict а также use warnings, Это может спасти вас от множества опечаток.

Операции с новым блоком

Я бы сказал, что возможность расширения языка, создания псевдоблочных операций - одна из них.

  1. Вы объявляете прототип для подпрограммы, указывающей, что она сначала берет ссылку на код:

    sub do_stuff_with_a_hash (&\%) {
        my ( $block_of_code, $hash_ref ) = @_;
        while ( my ( $k, $v ) = each %$hash_ref ) { 
            $block_of_code->( $k, $v );
        }
    }
    
  2. Затем вы можете назвать это в теле так

    use Data::Dumper;
    
    do_stuff_with_a_hash {
        local $Data::Dumper::Terse = 1;
        my ( $k, $v ) = @_;
        say qq(Hey, the key   is "$k"!);
        say sprintf qq(Hey, the value is "%v"!), Dumper( $v );
    
    } %stuff_for
    ;
    

(Data::Dumper::Dumper это еще одна скрытая жемчужина.) Обратите внимание, что вам не нужно sub Ключевое слово перед блоком или запятая перед хешем. Это выглядит так: map { } @list

Исходные фильтры

Также есть исходные фильтры. Где Perl передаст вам код, чтобы вы могли им манипулировать. И то, и другое, и операции с блоками, в значительной степени не относятся к типу "не пытайся это дома".

Я сделал несколько полезных вещей с исходными фильтрами, например, создал очень простой язык для проверки времени, позволив коротким однострочникам Perl для принятия решения:

perl -MLib::DB -MLib::TL -e 'run_expensive_database_delete() if $hour_of_day < AM_7';

Lib::TL будет просто сканировать как "переменные" и константы, создавать их и подставлять их по мере необходимости.

Опять же, исходные фильтры могут быть грязными, но мощными. Но они могут испортить отладчикам что-то ужасное - и даже предупреждения могут быть напечатаны с неправильными номерами строк. Я перестал использовать Damian's Switch, потому что отладчик потерял бы всю способность говорить мне, где я на самом деле был. Но я обнаружил, что вы можете минимизировать ущерб, изменяя небольшие фрагменты кода, сохраняя их в одной строке.

Сигнальные Крючки

Это достаточно часто делается, но не все так очевидно. Вот обработчик кубика, который копилку на старом.

my $old_die_handler = $SIG{__DIE__};
$SIG{__DIE__}       
    = sub { say q(Hey! I'm DYIN' over here!); goto &$old_die_handler; }
    ;

Это означает, что всякий раз, когда какой-то другой модуль в коде хочет умереть, он должен прийти к вам (если кто-то другой не сделает деструктивную перезапись на $SIG{__DIE__}). И вы можете быть уведомлены, что кто-то что-то считает ошибкой.

Конечно, для достаточно вещей вы можете просто использовать END { } заблокировать, если все, что вы хотите сделать, это очистить.

overload::constant

Вы можете проверять литералы определенного типа в пакетах, которые включают ваш модуль. Например, если вы используете это в своем import суб:

overload::constant 
    integer => sub { 
        my $lit = shift;
        return $lit > 2_000_000_000 ? Math::BigInt->new( $lit ) : $lit 
    };

это будет означать, что каждое целое число больше 2 миллиардов в вызывающих пакетах будет изменено на Math::BigInt объект. (Смотрите перегрузка:: константа).

Сгруппированные целочисленные литералы

Пока мы на этом. Perl позволяет разбивать большие числа на группы по три цифры и при этом получать из них целое разборное число. Заметка 2_000_000_000 выше за 2 млрд.

На основании того, как "-n" а также "-p" Переключатели реализованы в Perl 5, вы можете написать, казалось бы, некорректную программу, в том числе }{:

ls |perl -lne 'print $_; }{ print "$. Files"'

который конвертируется внутренне в этот код:

LINE: while (defined($_ = <ARGV>)) {
    print $_; }{ print "$. Files";
}

Это мета-ответ, но архивы Советов Perl содержат все виды интересных трюков, которые можно сделать с помощью Perl. Архив предыдущих советов доступен для просмотра в Интернете и может быть подписан через список рассылки или атомную ленту.

Некоторые из моих любимых советов включают создание исполняемых файлов с использованием PAR, использование autodie для автоматического генерирования исключений и использование конструкций switch и smart-match в Perl 5.10.

Раскрытие информации: я один из авторов и сопровождающих Perl Tips, так что я, очевидно, очень высоко ценю их.;)

Давайте начнем с оператора космического корабля.

$a = 5 <=> 7;  # $a is set to -1
$a = 7 <=> 5;  # $a is set to 1
$a = 6 <=> 6;  # $a is set to 0

map - не только потому, что он делает код более выразительным, но и потому, что он дал мне импульс прочитать немного больше об этом "функциональном программировании".

Предложение продолжения для циклов. Он будет выполняться в нижней части каждого цикла, даже тех, которые находятся рядом.

while( <> ){
  print "top of loop\n";
  chomp;

  next if /next/i;
  last if /last/i;

  print "bottom of loop\n";
}continue{
  print "continue\n";
}

Мой голос был бы за (?{}) И (??{}) группы в регулярных выражениях Perl. Первый выполняет код Perl, игнорируя возвращаемое значение, второй выполняет код, используя возвращаемое значение в качестве регулярного выражения.

m// Оператор имеет несколько неясных особых случаев:

  • Если вы используете ? в качестве разделителя он совпадает только один раз, если вы не позвоните reset,
  • Если вы используете ' в качестве разделителя шаблон не интерполируется.
  • Если шаблон пуст, он использует шаблон из последнего успешного совпадения.
while(/\G(\b\w*\b)/g) {
     print "$1\n";
}

Якорь \G. Жарко

Алмазный оператор с нулевой файловой ручкой<> имеет свое место в создании инструментов командной строки. Действует как <FH> читать из дескриптора, за исключением того, что он волшебным образом выбирает, что будет найдено первым: имена файлов командной строки или STDIN. Взято из перлопа:

while (<>) {
...         # code for each line
}

Специальные блоки кода, такие как BEGIN, CHECK а также END, Они происходят из Awk, но в Perl работают иначе, потому что они не основаны на записях.

BEGIN блок может использоваться для указания некоторого кода для фазы синтаксического анализа; это также выполняется, когда вы делаете проверку синтаксиса и переменных perl -c, Например, чтобы загрузить переменные конфигурации:

BEGIN {
    eval {
        require 'config.local.pl';
    };
    if ($@) {
        require 'config.default.pl';
    }
}
rename("$_.part", $_) for "data.txt";

переименовывает data.txt.part в data.txt без необходимости повторяться.

Немного неясен "оператор" тильды-тильды, который задает скалярный контекст.

print ~~ localtime;

такой же как

print scalar localtime;

и отличается от

print localtime;

Разделитель входных записей может быть установлен на ссылку на число для чтения записей фиксированной длины:

$/ = \3; print $_,"\n" while <>; # output three chars on each line

Оператор козла*:

$_ = "foo bar";
my $count =()= /[aeiou]/g; #3

или же

sub foo {
    return @_;
}

$count =()= foo(qw/a b c d/); #4

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

* Обратите внимание, на самом деле не оператор

"Режим отчаяния" конструкций управления циклами Perl, который заставляет их искать в стеке, чтобы найти подходящую метку, допускает некоторые любопытные поведения, которыми пользуется Test::More, к лучшему или к худшему.

SKIP: {
    skip() if $something;

    print "Never printed";
}

sub skip {
    no warnings "exiting";
    last SKIP;
}

Там есть малоизвестный файл.pmc. "use Foo" будет искать Foo.pmc в @INC до Foo.pm. Это было сделано для того, чтобы сначала загружать скомпилированный байт-код, но Module::Compile использует это для кэширования исходно отфильтрованных модулей для ускорения загрузки и отладки.

Возможность превращать предупреждения в ошибки.

local $SIG{__WARN__} = sub { die @_ };
$num = "two";
$sum = 1 + $num;
print "Never reached";

Это то, что я могу придумать, не упомянув.

Другие вопросы по тегам