Perl


комментарии

    # это строка комментария 

многострочные комментарии

   =somemark

   любой текст здесь
   вплоть до "=cut" (with = prefix) в самом начале строки

   =cut 

scopes

по умолчанию все переменные глобальны, если только они явно не обьявлены с квантификатором my

  sub mfunction {
    my ($n, $s, $d, $x, $k) = @_ ;
    ...
  }

переменная по умолчанию $_

в ОГРОМНОМ количестве функций при опускании аргумента она подразумевается по умолчанию. она также по умолчанию сопоставляется с регулярным выражением. пример:

  @Data = <STDIN> ;
  foreach (@Data) { chomp; print if /^From:/ ; }

аналогичен такому:

  @Data =  ;
  foreach $_  (@Data) { chomp $_ ; print $_ if $_ =~ /^From:/ ;

строки

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

    $var =~ /TEMPLATE/                       # matching - возвращает 1 или "" 
    $var =~ m/TEMPLATE/                      # matching - возвращает 1 или "" 
    $var =~ s/TEMPLATE1/TEMPLATE2/flags      # substitution - возвращает измененную строку

например скрипт matching.pl :

$var = "abc" ;
print ($var =~ m/a/) ; print "\n" ;
print ($var =~ m/b/) ; print "\n" ;
print ($var =~ /d/) ; print "\n" ;
print $var . "\n" ;
$var =~ s/b/kkk/ ;
print $var . "\n" ;
выведет :
$> perl matching.pl 
1
1

abc
akkkc

у команды s/.../.../ есть очень полезный флаг e — он означает, что вторая строка - не строка, а выражение, РЕЗУЛЬТАТ которого и будет подставлен

например, есть файл в котором все записи о возрасте через год надо менять:

      open (OLD, >> "oldfile.txt") || die "cannot open oldfile.txt $!\n" ;
      open (NEW, >> "newfile.txt") || die "cannot open newfile.txt $!\n" ;
      
      foreach (<OLD>)
      {
        s/ (\d+) (\s+$)/ ($1+1).$2/gie ;
        print NEW $_ ;
      } ;
      
      close (NEW) ;
      close (OLD) ;

substr

  substr ($mystring,0,12) ;  # offset, length

  substr ($mystr,10) ;       # offset

split , join

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

       @WordList = split (/ / , $String) ;

после обработки снова обьединить:

        $String = join (' ' , @WordList) ;

конкатенация строк

          .=
    и 
          .

    $str0 = $str1 . str2
    $str10 .= $str11 . $str12

ввод/вывод

    read EXP1, SCALAR, LENGTH, OFFSET
    read EXP1, SCALAR, LENGTH
    
    print EXP1, [EXPR2, ... ] ;
    print FD EXP1 [, EXPR2, ... ] ;

    printf "%6d %-20s\n", $tot, $name ; 

циклы

классика жанра:

    if (COND) { ... } ;
    print "ok" if (COND) ;

    while (COND) { ... } ; 

в пару к оператору if имеется оператор unless, означающий "if с отрицанием":

      unless ( COND )  { ... }

      print "Ok" unless $x < $y ;

также в пару while существует until

    until (COND) { ... } ;
    print "ok" until (COND) ;
  

синтаксис оператора for полностью аналогичен С:

      for ( $i = 0 ; $i < 10 ; $i++) { ... }

оператор foreach, позволяющий пройтись по всем элементам массива, присваивая по очереди его элементы какой-то переменной, имеет такой синтаксис :

      foreach $var (@somearray) { ... }
или
    foreach  (@somearray) { ... }
это очень функциональный способ работы с коллекциями!

функциональщина

вместо "filter" используем grep BLOCK LIST

my @rra = grep { $_ > 3 } (1,2,3,4,5) ;
print foreach (@rra) ; #  45 

а "map" остался "map"ом: map BLOCK LIST

my @rra = map { $_ + 42 } (1,2,3,4,5) ;
print foreach (@rra) ; # 4344454647

fold в Perl выглядит так:

  $acc ; foreach (@somearr) { $acc = ... } 

примеры:

$ perl -e '
> $acc = 0 ;
> @m = (1,2,3,4,5,6) ;
> foreach (@m) { $acc += $_ } ;
> print $acc ;
> '
21

##########################################################
#! /usr/bin/perl -w
use strict;

sub foldl {
    my ($fn, $acc, @list) = @_;

    foreach my $foo (@list) {
        $acc = &$fn ($acc, $foo) ;
    }

    return $acc;
}

sub foldl1 {
    my ($fn, @list) = @_ ;

    my $acc = shift @list ;

    return &foldl ($fn, $acc, @list) ;
}

sub foldr {
    my ($fn, $acc, @list) = @_ ;

    foreach my $foo (reverse @list) {
        $acc = &$fn ($foo, $acc) ;
    }

    return $acc ;
}

sub foldr1 {
    my ($fn, @list) = @_ ;

    my $acc = pop @list ;

    return &foldr ($fn, $acc, @list) ;
}
#####################################################################

патерн-матчинг

можно обращаться к нескольким "выбранным" элементам массива ("срезу"):

      @list = (1..10) ;
      @list[0,1,2,4,9] = (A,100,200,300,400) ;    #  A,100,200,4,300,6,7,8,400,10
      @list[1,9] = @list[9,1] ;                   #  A,10,200,4,300,6,7,8,400,100 

ссылки на функции - первокласные обьекты

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

      $code_reference->(arg1,...,argN) ;

сериализация

pack и unpack

вот в Си есть такая идиома:

#include <stdio.h>
#include  <stdlib.h>

int
main (int argc, char** argv, char** envp)
{
  char* mstr ;

  scanf  ("%s",   &mstr) ;
  printf ("%s\n",  mstr) ; 

  return 0 ;
}

так вот - в Perl есть нечто подобное - но для байтов:

      my $x = pack   'L' , 12 ;
      my $y = umpack 'L' , $x ;

разные утилитки

генератор случайных чисел

     rand                    # float 0 .. 1
     rand EXPR               # float 0 .. EXPR
     
     srand                   # seed random generator by OS kernel
     srand EXPR              # seed random generator by EXPR   

пауза выполнения скрипта

      sleep EXPR 

файловый ввод-вывод

      open FH, MODE, FILE
      open FH, EXPR
возвращает 0 при неудаче и 1 при успешном открытии файла
    print FH, LIST
    close FH
    
    while (<FH>) { ... } 

   eof FH 
возвращает TRUE или FALSE

пример:

   open (Fh1, "<file.txt") || die "couldn't open file file.txt, $!" ; 

   while (<Fh1>) {
        print "$_" ;
   }
чтобы открыть файл в режиме дописывания:
   open (Fh1, ">>file.txt") || die "couldn't open file file.txt, $!" ;

полезные утилитки работы с файлами:

   unlink FILE      # удалить файл
   unlink LIST      # удалить файлы
   chomp $str       # строка без завершающего символа EOL (при чтении из файлов)

учебник


в Perl существует всего пять видов объектов. это

причем понятие 'список' — особое

СКАЛЯР

скалярная переменная Perl может хранить одно из трех значений: строку, число или же ссылку. точка. скалярные переменные всегда начинаются c $

ссылка в Perl — это скаляр, который содержит адрес некоторого объекта, НО НЕ СПИСКА!

СПИСОК

список задает в программе последовательность скаляров. он может быть гетерогенным

список в программе на Perl задается в круглых скобках любого уровня вложенности:

     ( 1, 2, 3 )
     ( ( (1, 2, 3) ) )
     ( (1), (2), (3) )
таким образом, все три приведенные выше строчки задают один и тот же список, содержащий числа 1, 2 и 3. вложенность скобок не играет никакой роли — хоть всю программу ими обвешайте

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

попробуйте теперь догадаться, что будет, если присвоить список скаляру:

  $a =  (10,20,30) ;
оказывается, в этом случае в переменной окажется значение последнего элемента списка, то есть 30. Первые два элемента безвозвратно потерялись, это и понятно: нельзя все величины сохранить в малюсеньком скаляре

когда в программе вы пишете A = B, перед присваиванием Perl переводит B либо в список, либо в скалярное значение (в зависимости от вида A)

этот момент иногда оказывается весьма существенным. Например, функции могут возвращать либо скаляр, либо список, и ничто иное. Они не могут вернуть ни массив, ни хэш

раз существует всего два типа «обменных» данных, должны существовать и какие-то правила перевода одного типа в другой. Эти правила довольно просты

МАССИВ

    @A =  (10,20,30) ;
в такой ситуации в массив должно быть помещено три элемента, перечисленных в списке

массив может быть гетерогенным

увы, массивы в Perl могут содержать только скаляры. В ранних версиях языка (четвертой и ниже) нельзя было создать даже двумерного массива. Однако в пятой версии ситуация кардинальным образом изменилась: появились специальные скалярные значения, так называемые ссылки на другие объекты. Теперь можно создать двумерный массив как массив ссылок на массивы скаляров. И, хотя массивы и хэши по-прежнему хранят только скаляры, теперь к «лику скаляров» причислены также и ссылки, а значит, нам развязали руки

если Perl видит слева нечто, начинающееся с @, а справа — список, то он понимает, что происходит присваивание значения массиву и поступает соответственно. таким образом, само обозначение «с собакой» используется только в том случае, когда имеется в виду массив целиком - для обращения к конкретному элементу массива по-прежнему необходимо применять доллар - "деньги не пахнут"

настало время посмотреть, как массивы преобразуются в список и в скаляр

со списком все ясно — его элементами просто становятся элементы массива

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

    # помещаем в $a число элементов @A
    $a = @A;
    # помещаем в @B все, что было в @A,
    # и еще парочку элементов
    @B =  (1, @A, 2) ; 

для явного указания того, что выражение нужно трактовать в скалярном контексте, существует специальный оператор scalar. он обычно используются в случае, если по выражению слева не видно, какой именно контекст должен использоваться (по умолчанию же всегда подразумевается списковый контекст):

  # вывести число элементов хэша
  @K = keys %data;
  print scalar  (@K) ;
функция print подразумевает для своих аргументов списковый контекст, поэтому, написав print @K, мы бы вывели на экран значения ключей, но никак не их количество. давайте теперь упростим этот код — избавимся от временной переменной @K. итак, вот программа, которая выдаст нам тот же самый результат:
  # вывести число элементов хэша
  print scalar (keys %data) ;
нетрудно понять, что делает данный код: вначале он при помощи функции keys получает список всех ключей хеша %data, а затем трактует этот список в скалярном контексте и получает... так, м-ммм... листаем наши конспекты... последний элемент списка? но это же совсем не то, что мы хотели!

на самом деле - все в порядке, и программа работает как надо. дело в том, что в данном примере функция keys возвращает не список, а прямо сразу число — количество элементов. как же она узнает, когда нужно возвращать число, а когда — список ключей? об этом заботится оператор scalar: он передает вызываемой функции специальный флажок, который говорит, вызвана она в скалярном или в списковом контексте

скалярный контекст для получения числа элементов массива (но не списка!) удобно применять, например, в цикле for:

   for (my $i = 0 ; $i < @A ; $i++)  {...}
это выглядит несколько лучше, чем такой код:
   for (my $i = 0 ; $i < $#A ; $i++)  {...}
на всякий случай - еще пару примеров работы с массивами:
    # получаем элемент массива
    $a = $A[$i*2-1] ;

    # последний элемент - вот так просто
    $b = $A[-1] ;

    # предпоследний и последний элементы
     ($a, $b) =  ($A[-2], $A[-1]) ;
в последнем примере мы видим, что список — это универсальное понятие, потому что его можно использовать в левой части оператора присваивания
    # перебор массива
    foreach my $elt  (@A)  {...}

    # или по-другому
    for (my $i = 0 ; $i<@A ; $i++)  {...}

    # добавление элемента в конец массива
    push @A, 10 ;

    # добавление трех элементов (можно без скобок)
    push @A, (10, 20, 30)

    # добавление массива @B в начало @A
    unshift @A, @B ;

ХЭШ

никогда не путайте массивы и хэши — они не могут преобразовываться друг в друга никак иначе, кроме как посредством обмена списковыми значениями. то есть, вы можете «присвоить переменной типа хэш переменную типа массив», но в действительности произойдет присваивание хэшу списка значений, в которые преобразовался массив. что же происходит, когда хэшу присваивают список?.. все очень просто: четные элементы списка (начиная с нулевого) становятся ключами, а нечетные — соответствующими значениями:

    %H =  (
        'a', 'aaa',     # первая пара "ключ-значение"
        'b', 'bbb',     # вторая пара
        'c', 'ccc',     # третья
    ) ;
запятая в конце последней пары допускается, это не ошибка

обилие апострофов раздражает, а потому в Perl был придуман новый знак пунктуации — стрелочка =>, которая ведет себя идентично запятой, однако позволяет указывать слева от себя слово без апострофов, не выдавая предупреждений:

    %H =  (
        a => 'aaa',    # первая пара "ключ-значение"
        b => 'bbb',    # вторая пара
        c => 'ccc',    # третья
    ) ; 

хеш может быть гетерогенным

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

когда хэш трактуется в списковом контексте, он превращается в 2*N значений, где N — число пар ключ-значение в хэше. порядок следования элементов в полученном списке будет непредсказуемым — это специфика работы с хэшами в Perl - получая доступ по ключу, вы за это расплачиваетесь «порядочностью» значений. везде, где требуется предсказуемый порядок элементов, используйте массивы, а где поиск по ключу — хэши. это дисциплинирует

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

    # присваиваем значение хэшу целиком
    %H = (a => 'aaa', b => 'bbb') ;

    # а можно и так
    $H {a} = 'aaa' ;

    # получаем доступ по ключу
    my $x = $H {'a'} ;
наконец, когда хэш трактуется в скалярном контексте, он возвращает довольно интересную строку, которая выглядит вот так: M/N. Здесь M — число ключей в хэше, а N — это количество свободного места, которое еще есть в памяти для данного хэша

удаление из хеша:

      delete $hash{1};

функции выдающие ключи и значения:

      %hash =  (A,20,2,100,3,'doom') ;
      @k    = keys %hash ;              #  @k =  (A,2,3) ;
      @v    = values %hash ;            #  @v =  (20,100,'doom') ;

ну и несколько примеров работы с хэшами

    # создаем хэш из списка
    %H = (a = >10, b = >20, c = >30) ;

    # перебираем все элементы
    while (my  ($k, $v) = each (%H)) {...}

    # перебираем ключи в алфавитном порядке
    foreach my $k (sort keys %H) {...}

    # добавляем элемент в хэш
    $H {d} = 40 ;

    # удаляем элемент из хэша
    delete $H {a} ;

    # проверяем существование ключа
    if (exists $H {b})  {...}

в качестве резюме:

  --------------------------------------------------------------------------
     что преобразуем      тип          в скаляр          в список
  --------------------------------------------------------------------------
     $a                 скаляр            -             (значение)
     (3,4,5)            список      последний элемент      -
     @b                 массив      число элементов     (элементы)
     %c                 хэш            M/N              (k1,v1, k2,v2, ...)
  --------------------------------------------------------------------------

ФУНКЦИИ

обьявление:

sub NAME

определение:

sub NAME BLOCK

импорт:

use MODULE qw (NAME1, NAME2, ...) ;

вызов:

    NAME (LIST)
    NAME LIST              # если есть обьявление
    &NAME                  # передается текущее значение @_
    &$subref               # передается текущее значение @_
    &$subref (LIST)
    &$subref->(LIST)
все параметры передаются как один плоский список скаляров. внутри функции этот массив @_ локален, но содержит ссылки на значения. если метод передачи по ссылке не устраивает, то внутри функции необходимо выполнять присваивания локальным переменным и дальше работать только с локальными переменными

множественные значения возвращаются как один плоский список скаляров

команда return без аргументов возвращает в скалярном контексте undef, а в списочном - нулевой список

системная функция wantarray возвращает undef, если ваша функция вызвана в пустом контексте:

  if  ($some_err)  {
    return if defined wantarray ;
    die "something wrong" ;
  }

ССЫЛКА

ссылка в Perl — это скаляр, который содержит адрес некоторого объекта, как-то: массив, хэш или другой скаляр. в дальнейшем, используя этот адрес, мы можем к объекту обратиться — это так называемое "разыменование ссылки"

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

ссылка имеет право ссылаться не только на массив и хэш, но также и на скаляр. но ведь в этом скаляре вполне может содержаться другая ссылка. в результате получится ссылка на ссылку на объект? именно так - и для доступа к нему потребуется выполнить операцию разыменования ДВАЖДЫ

любителям Си стоит обратить внимание на то, что ссылка — это не указатель и поэтому с ней можно сделать лишь две вещи:

  • разыменовать (т.е, получить доступ к объекту)
  • и удалить (т.е, присвоить ссылке неопределенное значение — undef)
  • но нельзя сложить ссылку с числом или умножить ссылку на число

    одной ссылке можно также присвоить значение другой (и мы получим две ссылки на один и тот же объект, а не две копии объекта)

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

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

      -------------------------------------------------
        значение    тип скаляра
      -------------------------------------------------
        ""          скаляр не является ссылкой
        SCALAR      ссылка на скаляр
        ARRAY       ссылка на массив
        HASH        ссылка на хэш
        CODE        ссылка на функцию
        GLOB        ссылка на элемент таблицы символов
      -------------------------------------------------
    

            use strict;
            use warnings;
    
            my @arr = ('a', 'b', 'c');
            my %hash;
            $hash {letters} = \@arr;
    
            say ref $hash {letters};
    
            --output:--
            ARRAY
    
    такой вывод не означает, что $hash{letters} есть массив! он означает,что $hash{letters} есть ссылка на массив. 'ref' вернет пустую строку если ее аргумент - не ссылка

    вот пример использования ref:

        # выводит тип ссылки
        print ref ($r) ; 
    имея имя некоторого объекта, мы можем создать ссылку на него, используя оператор \ (обратный слэш):
        $r = \ ВЫРАЖЕНИЕ; 
    в качестве ВЫРАЖЕНИЯ может выступать все, что угодно, начиная от простого указания имени объекта и кончая арифметическим или другим выражением, которое будет вычислено. в последнем случае результат помещается во временную память, а затем возвращается ссылка на эту память. вот несколько примеров:
      # получаем ссылку на массив @A
      $r = \ @A;
    
      # ссылка на хэш %A  (хотя имя у него и похоже на имя @A, это разные объекты)
      $r = \ %A;
    
      # ссылка на скаляр $a
      $r = \ $a;
    
      # ссылка на константу - то же самое, что ссылка на скаляр, но объект read-only
      $r = \ "test";
    
      # ссылка на ссылку на массив
      $r = \ \ @A;
    
      # ссылка на ссылку на значение выражения
      $r = \  (1+2*sin (10)) ;
    
      # ссылка на функцию программы
      $r = \ &myFunc;
    
      # ссылка на элемент таблицы символов
      $r = \ *someElt;
    
      # ссылка сама на себя  (лучше так не делать)
      $r = \ $r; 

    как видим, можно создать ссылку на ЛЮБОЙ объект Perl, будь то массив, хэш или даже функция. «любой объект», потому что только на объект Perl можно создать ссылку. например список в Perl не является объектом (это — просто промежуточное представление данных), а потому создать ссылку на список в Perl нельзя

      # создание нового массива и ссылки на него
      $rA = [СПИСОК] ;
    здесь СПИСОК — это любое выражение, которое трактуется в списковом контексте. в частности, это может быть результат, который вернула некоторая функция. вот несколько примеров:
      # ссылка на список "на лету"
      $rA = [ (1,2,3) ] ;
    
      # то же самое, но лаконичнее
      $rA = [1,2,3] ;
    
      # создаем ссылку на пустой массив
      $rA = [] ;
    
      # ссылка на массив ссылок на массивы
      $rA = [
        [1,2,3],
        [2,3,4],
        [3,4,5],
      ] ;
    
      # ссылка на массив ключей хэша %H
      $rK = [keys %H] ;
    обратите внимание на последний пример: было бы ошибкой написать вот так:
      # неверный код!
      $rK = \ (keys %H) ;
    

    а все из-за того, что функция keys не может возвратить ничего, кроме списка, а при взятии \ от списка мы получаем список ссылок, в скалярном контексте — т.е. ссылку на ПОСЛЕДНИЙ элемент. будьте внимательны!

    итак, существует всего два способа создать ссылку на массив:

  • использовать \ @что_то
  • использовать [что-то]
  • все остальные способы не сработают в принципе

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

      # если имеем переменную-хэш - то так:
      %someHash =  (a = >1, b = >2, c = >3) ;
      $rH = \ %someHash;
    
      # а если не имеем, то вот так:
      $rH = {a = >1, b = >2, c = >3};
    
      # ссылка на пустой хэш
      $rA = {};
    для хэшей также существует только ДВА СПОСОБА создать ссылку: применить синтаксис
      \ %что_то
    либо же
      {что-то}  

    есть разница между следующими двумя строками:

      # некоторый хэш
      %H = (a = >1, b = >2) ;
    
      # ссылка на существующий хэш
      $r = \%H;
    
      # ссылка на новый хэш
      $r = {%H};

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

        $H {a} = 0
    либо же через ссылку (разыменовав ее)

    во втором случае происходит совершенно другое: вначале на основе хэша создается список его элементов (чередуются ключи и значения), потом этот список преобразуется в «безымянный» хэш (по правилу преобразования: четные элементы становятся ключами, нечетные — значениями), и уж только потом возвращается ссылка на полученный хэш. первая строчка выполняется очень быстро, вне зависимости от того, сколько миллионов элементов было в %H. вторая же, напротив, работает медленно. ведь мало того, что нужно выделить дополнительную память и создать там список, необходимо его затем еще и упаковать в хэш, А ЭТО ОЧЕНЬ ДЛИТЕЛЬНЫЙ ПРОЦЕСС

    разумеется, это правило справедливо и для массивов: конструкция

        [@A]   
    создаст новый массив и вернет ссылку на него, а конструкция
        \@A  
    даст ссылку на уже имеющийся в программе массив

    метод создания массива и хэша с использованием скобок [] и {} называется созданием анонимного массива или хэша. вообще, «анонимным» называется объект, доступный исключительно посредством ссылок - то есть, добраться до него можно ТОЛЬКО в процессе разыменования

    разыменования ссылок:

    ссылки бывают "жесткие" и "мягкие". первые считают использованные референсы и автоматом собирают мусор - если счетчик обнулится, то обьект ссылки удаляется. "мягкие" ссылки - это просто имена переменных (почти как symbolic link в файловой системе Unix). например нотация *glob это и есть "мягкая" ссылка

    пути создания ссылок:

    1. используя оператор backslash
              $scalarref = \ $foo;
              $arrayref  = \ @ARGV;
              $hashref   = \ %ENV;
              $coderef   = \ &handler;
              $globref   = \ *foo;
      
      но таким способом невозможно создать "жесткую" ссылку на IO handle (filehandle)
    2. используя square brackets (только для массивов)
              $arrayref = [1, 2, ['a', 'b', 'c']];
      так можно создать ссылку на анонимный массив. после этого $arrayref->[2][1] будет иметь значение "b"
    3. ссылка на список не то же самое, что ссылка на анонимный массив!
              @list = (\ $a, \ @b, \ %c) ;
              @list = \ ($a, @b, %c) ;      # same thing!
      
      \(@foo) возвратит СПИСОК ссылок на содержимое @foo , а не ссылку на сам массив @foo и то же самое касается хеша %foo
    4. ссылка на анонимный хеш может быть создана с помощью curly brackets
              $hashref = {
                  'Adam'  => 'Eve',
                  'Clyde' => 'Bonnie',
              };
      NB: из-за того, что curly brackets используются для BLOCKs, иногда вам придется устранять неоднозначность помещая в начало statement знак '+' или слово 'return'. например:
              sub hashem {        { @_ } }   # wrong
              sub hashem {       +{ @_ } }   # ok
              sub hashem { return { @_ } }   # ok
    5. ссылка на лямбду может быть создана использованием слова 'sub' без имени:
              $coderef = sub { print "Boink!\n" } ;

    идиомы Perl:

                $bar                = $$scalarref;
                push (@$arrayref, $filename);
                $$arrayref[0]       = "January";
                $$hashref {"KEY"}   = "VALUE";
                &$coderef (1, 2, 3);
    "простой скаляр" позволяет включать свой идентификатор в выражения рекурсивно и поэтому такой кусочек кода напечатает "howdy":
                $refrefref = \\\"howdy";
                print $$$$refrefref;
    в любом месте, где правомочно использование идентификатора, вы можете заключить его имя в BLOCK - такая конструкция вернет верную ссылку. предыдущие строчки можно записать так:
            $bar                 = ${$scalarref};
            push (@{$arrayref}, $filename);
            ${$arrayref}[0]      = "January";
            ${$hashref}{"KEY"}   = "VALUE";
            &{$coderef}(1, 2, 3);
    BLOCK может содержать что угодно - лишь бы содержимое выдавало обьект:
            &{ $dispatch{$index} }(1,2,3);        # диспетчирезация функций
    
    "почуствуйте разницу" - case 0 есть короткая версия case 1, но не case 2:
            $$hashref{"KEY"}     = "VALUE";       # case 0
            ${$hashref}{"KEY"}   = "VALUE";       # case 1
            ${$hashref{"KEY"}}   = "VALUE";       # case 2
            ${$hashref->{"KEY"}} = "VALUE";       # case 3
    
    case 2 не есть case 3

    еще несколько неочевидных примеров:

            $name      = "foo";
            $$name     = 1;             #  sets $foo
            ${$name}   = 2;             #  sets $foo
            $name->[0] = 4;             #  sets $foo[0]
            @$name     = ();            #  clears @foo
            &$name();                   #  calls &foo()

    чтобы случайно не создать "мягкую ссылку" вместо "жесткой" вы можете использовать прагму

            use strict 'refs';
    а где-нибуть внутри блока если вам понадобится "мягкая ссылка" то локально отменить такую прагму другой:
            no strict 'refs';
    еще раз - для "мягких ссылок" доступны только переменные модуля (т.е. глобальные даже если они локализованы в BLOCK). локальные переменные (задекларированные с my) просто не находятся в таблице символов:
            local $value = 10;
            $ref = "value";
            {
                my $value = 20;
                print $$ref;        # 10
            }

    теперь, еще одно важное замечание по поводу скобок {}:

            $push = "pop on ";
      
            print "${push}over";             # "pop on over"
            print ${ push } . "over";        # "pop on over"

    помним, что

            use strict 'refs';
            ${ bareword };      # ok, means $bareword
            ${ "bareword" };    # error, symbolic reference! 

    вы можете ЗАСТАВИТЬ компилятор распознать ключевое слово - просто добавив что-нибуть, что сделает его значимым:

            $hash { shift()  }
            $hash { +shift   }
            $hash { shift @_ }

    НИКОГДА НЕ ИСПОЛЬЗУЙТЕ ССЫЛКИ В КАЧЕСТВЕ КЛЮЧЕЙ ХЕША!

    лямбды

    код, создающий ссылку на функцию:

      # ссылка на функцию программы
      $r = \ &myFunc; 
    здесь можно заметить известную аналогию с массивами и хэшами, только вместо % и @ используется &. в тот раз нам удалось обойтись без создания временного объекта — мы использовали конструкции [] и {} для получения анонимных объектов. можно ли применить этот прием для получения безымянных функций?... оказывается, да, и выглядит это следующим образом:
      # создание ссылки на анонимную функцию
      $rF = sub {
          print "мы в функции!\n" ;
          foreach (1..2)  { print "$_\n" }
          return 10 ;
      } ;

    здесь нужно обратить внимание на два момента. во-первых, не забудьте указать ; после определения тела функции — здесь ее пропускать нельзя, как нельзя пропускать, например, при объявлении анонимного хэша. во-вторых, инструкция создания функции выглядит в общем виде как sub {...}, и слово sub является обязательным. именно по слову sub Perl и определяет, что программист желает создать функцию, а не хэш

    замыкания

    с созданием анонимных функций связано одно важное понятие — замыкание (closure). замыкания Perl позволяют сделать код программы равноправным с ее данными:

    sub g {
      my ($name, $count) = @_ ;
      return sub { print "$name : " . $count++ . "\n" } ;
    } ;
    
    my $a = g ("A", 10);
    my $b = g ("B", 20);
    
    &$a () ;
    &$a () ;
    &$b () ;
    &$b () ;
    &$a () ;
    &$b () ;

    хаки

    для установки модуля с помощью CPAN, но в нужную директорию:

    $> cpan
    cpan> o conf makepl_arg INSTALL_BASE=/path/to/my/dir
    cpan> o conf commit  

    для отладки скрипта CGI в командной строке:

    $> echo -n 'param = val' | REQUEST_METHOD = POST CONTENT_LENGTH = 9999 perl file.cgi

    определить , установлен ли Perl module:

    $> perl -mCGI::Cookie -e 'print "good!\n";'
    
    $> perl -MImage::Magick -e 1
    
    $> perl -MJSON -e 1
    
    $> perl -mDBI -e 1

    полезная кобинация

              $> perl -lane 'some script commands' file 
    делает perl похожим на awk или sed. можно также указать полевые разделители -F: (знак ':' вместо пробела)

    ключи для проверки файлов : -e -r -w -d -x -B -T

        if (-e $file1) { ...} 


    модули

    файлы с расширением *.pm и форматом:

    package Name;
    
    @EXPORT = qw(f1,  f2, f3, ..., fn);
    
    use vars qw(@EXPORT);
    
    sub f1 { ... }
    sub f2 { ... }
    sub f3 { ... }
    ...
    sub fn { ... }
    
    1;
    

    NB: модули обязательно должны возвращать 1 в конце


    cheat-sheets

      SIGILS         
      ----------------------
      $scalar        
      @array         
      %hash          
      &sub
      *glob
      ----------------------
    
    
      SCALAR VALUES:    number, string, reference, glob, undef
    
    
               ARRAYS          HASHES          
               --------------------------------
    whole:     @array          %hash           
    slice:     @array[0, 2]    @hash {'a', 'b'}
    element:   $array[0]       $hash {'a'}     
    
    
      REFERENCES
      --------------------------------------------------
      \        references       $$foo[1]        aka $foo->[1]
      $@%&*    dereference      $$foo{bar}      aka $foo->{bar}
      [ ]       anon.arrayref   $ {$$foo[1]}[2] aka $foo->[1]->[2]
      { }       anon.hashref    $ {$$foo[1]}[2] aka $foo->[1][2]
      \ ( )      list of refs
      --------------------------------------------------
    
    
                              NUMBERS vs STRINGS
      OPERATOR PRECEDENCE        =         =
      ->                      +         .
      ++ --                   ==    !=     eq    ne
      **                      < > <= >=  lt gt le ge
      ! ~ \ u+ u-             <=>        cmp
      =~ !~
      * / % x                 SYNTAX
      + - .                   for (LIST) { }     for (a; b; c) { }
      << >>       while ( )  { }     until ( ) { }
      named uops              if ( ) { }         elsif ( ) { }      else { }
      < > <=> =    lt gt le ge   unless ( ) { }   elsif ( ) { } else  { }
      == != <=> eq ne cmp ~~  for equals foreach  (ALWAYS)
      &
      | ^              REGEX METACHARS            REGEX MODIFIERS
      &&               ^     string begin         /i case insens.
      || //            $     str. end  (before \n) /m line based ^$
      .. ...           +     one or more          /s . includes \n
      ?:               *     zero or more         /x ign. wh.space
      =+ =- =* =etc.   ?     zero or one          /g global
      , =>             {3,7} repeat in range      /o cmpl pat. once
      list ops         ()    capture
      not              (?:)  no capture       REGEX CHARCLASSES
      and              []    character class  .  == [^\n]
      or xor           |     alternation      \s == whitespace
                       \b    word boundary    \w == word characters
                       \z    string end       \d == digits
                                              \S, \W and \D negate
    
    
      DO                       DON'T
      --------------------------------------------
      use strict;
      use warnings;            "$foo"
      my $var;                 $$variable_name
      open () or die $!;        `$userinput`
      use Modules;             /$userinput/
      --------------------------------------------
    
    
       SPECIAL VARIABLES
       -------------------------
        $_      default variable
        @_      subroutine args
        $0      program name
        $/      input separator
        $\      output separator
        $|      autoflush
        $!      sys/libcall error
        $@      eval error
        $$      process ID
        $.      line number
        @ARGV   command line args
        @INC    include paths
        %ENV    environment
       -------------------------