Последнее в категории Язык

«Почему Perl?»

| 1 комментарий

Отличный пост в живом журнале kovchiy, который нельзя обойти вниманием.

Автор побывал на YAPC::Europe 2011, купил книгу Learning Perl и рассказывает о том, что он понял из философии языка.

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

...

Perl — интересный и уникальный язык со своей историей развития и здравыми идеями. Просто иметь о нем представление уже полезный опыт для каждого программиста.

Хорошее чтение и просто так, и для общения с программистами на других языках.

$$_->[][]

| Комментариев: 7

Вот замечательное задание на собеседование.

Объясните разницу между $$_[0] и $_->[0].

Дополнительный вопрос: Есть ли неоднозначность в конструкции $$var[1][2]?

Мир до state

| Комментариев: 3

До прихода в Perl оператора state, который позволяет создавать «статические» переменные прямо внутри подпрограмм, люди пользовались вот таким приемом:

{
    my $count = 0;

    sub next_value {
        return ++$count;
    }

}

print next_value, "\n";
print next_value, "\n";


Теперь все ребята пишут так:

use v5.10;

sub next_value {
    state $count = 0;

    return ++$count;
}

say next_value;
say next_value;

Про $"

| Комментариев: 4

Еще один пример из того, что я ни разу не использовал, и даже не помнил о том, что такая возможность есть, но когда увидел в чужом коде, сильно обрадовался (хотя и пришлось потупить и поделать warn Dumper(...), прежде чем стало понятно).

Речь о переменной $", содержащей разделитель, который появится между элементами списка, если его интерполировать в двойных кавычках.

Очень удобно для того, чтобы делать SQL-запросы с ключевым словом in:

local $" = ',';
my $data = $dbh->selectall_hashref("
    select
        . . . 
    where
        id in (@$ids)
";

Замечательная задача для собеседования.

Дано: хеш вида

my %what_when = (
    13 => 'Lunch',
    17 => 'Tea',
    20 => 'Dinner',
     9 => 'Breakfast',
);

Требуется: сформировать список пар, отсортированных по ключу хеша (в примере — по времени):

my @schedule = (
    [9,  'Breakfast'],
    [13, 'Lunch'],
    [17, 'Tea'],
    [20, 'Dinner'],
);

В первой части были приведены три программы, работающие под Perl 5.12, и предлагалось определить, что они выведут.

А выведут они следующее.

Программа А.

use v5.12;
my @letters = 'a'..'z';
for (my ($number, $char) = each @letters) {
    say "$number $char";
}

0 a
0 a

Программа Б.

use v5.12;
my @letters = 'a'..'z';
say $_ for each @letters;

0
a

Программа В.

use v5.12;
my @letters = 'a'..'z';
say $_ foreach @letters;

a
b
c
. . .
x
y
z

Британец Барри Уолш пишет в своем блоге о важной особенности работы оператора each в Perl 5.12.

Вызов each, примененный к массиву, возвращает пару величин: индекс и значение очередного элемента. Очевидно, что в пределах цикла (напрмер, while) each сохраняет указатель на текущую позицию.

use v5.12;

my @letters = 'a'..'z';
while (my ($number, $char) = each @letters) {
    say "$number $char";
}

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

use v5.12;

my @letters = 'a'..'z';
while (my ($number, $char) = each @letters) {
    say "$number $char";
    last if $number == 15;
}

say "Second loop";
while (my ($number, $char) = each @letters) {
    say "$number $char";
}

В этом примере напечатается следующее:

0 a
1 b
2 c
. . .
14 o
15 p
Second loop
16 q
17 r
. . .
24 y
25 z

Видно, что each продолжил с того же места, где остановился в первом цикле.

Сбросить счетчик удается вызовом keys @array или values @array. Также важно, что изменение массива (с помощью push или pop) и даже присвоение новых значений не изменяет позицию счетчика:

use v5.12;

my @letters = 'a'..'z';
while (my ($number, $char) = each @letters) {
    say "$number $char";
    last if $number == 15;
}

@letters = 'A'..'Z';
say "Second loop";
while (my ($number, $char) = each @letters) {
    say "$number $char";
}

В этом случае второй цикл упрямо продолжит с того же места, но уже с другим содержанием:

0 a
1 b
2 c
. . .
14 o
15 p
Second loop
16 Q
17 R
. . .
24 Y
25 Z

В операторе when — будь он внутри «родного» блока given или внутри цикла for — обычно происходит смартматчинг переменной $_ с указанным выражением. В документации perlsyn перечислены искючения, однако есть и не слишком очевидное поведение, о котором нужно знать.

Вначале о том, что явно указано как исключения. Блок when(EXPR) не выполняет смартматчинг $_ ~~ EXPR, а является просто булевым выражением, если EXPR — одно из следущего:

  • Вызов функции или метода.
  • Регулярное выражение (тут надо помнить, что операторы =~ и ~~ ведут себя по-разному).
  • Сравнение (как с переменной по умолчанию, так и с любой друой) или явный смартматчинг.
  • Отрицание (!, not или xor).
  • Файловый тест.
  • Операторы .. и ....

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

when(0b1110_0000 == ($_ & 0b1111_0000))

Дополнительная проверка на равенство здесь необходима (даже если проигнорировать младшие биты). Прямолинейная битовая операция

when($_ & 0b1111_0000)

сравнивает переменную $_ со значением, полученным после битовой операции $_ & 0b1111_0000, и для проверки установленных битов нужно выполнять явное сравнение, которое входит в один из пунктов перечисленных выше исключений.

for vs. given

| 1 комментарий

Иногда вместо given удобно использовать for, например, чтобы сделать несколько проверок для каждого элемента массива.

Однако, эта легкость замены дает ложное ощущение возможности и обратного — использования given вместо for.

Есть такой старый трюк, когда for нужен лишь для того, чтобы топикализировать переменную и с легкостью пользоваться функциями, по умолчанию использующими $_.

Например:

for ($url) {
    s{\.?*}{};
    s{^/}{};
    s{/$}{};
}

Фактически никакого цикла здесь нет, и уж если подключен use 5.10, хочется использовать given. Однако, не тут-то было. Хотя given и создаст переменную $_, но она будет всего лишь лексической переменной в пределах блока given, а не синонимом $url.

use v5.10;
use strict;

my $string = 'Hello, Perl';
my $another = $string;

for ($string) {
    s/Hello/Hallo/;
    s/Perl/C++/;

}

given ($another) {
    s/Hello/Hi/;
    s/Perl/JavaScript/;

}

say $string;  # Hallo, C++
say $another; # Hello, Perl

Этот пример выведет измененную строку после блока с for и неизменную — после given. Будьте внимательны :-)

В серверном коде, обслуживащем сайт, блоки given/when весьма удобны в частности для того, чтобы последовательно протестировать URL запрошенного ресурса и выполнить соответствующие действия:

given($url) {
    when(m{^/$}) {home_page()}
    when(m{^/about/$} {about_page()}
    . . .
}

В Perl 5.10 помимо операторов given/when доступны именованные сохраняющие скобки, которые могут облегчить выделение параметров из адреса одновременно с его разбором:

given($url) {
    . . .
    when(m{^/news/(?<year>\d+)/(?<month>\d+)/(?<day>)/$})
        {news_that_day()}
}

Параметры, захваченные именованными скобками, попадают в хеши %+ и %-, которые следует передать дальше на обработку.

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

given($url) {
    . . .
}
say Dumper(\%+); #
Пусто

В этом месте кода переменные %+ и %- сохраняют значения, полученные до начала блока given.

Вплоне логично, хорошо локализовано, но не всегда удобно.

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

given($url) {
    . . .
    when(m{^/(?<type>this)_page/$})
        {%data = %+; do_this()}
    when(m{^/(?<type>that)_page/$})
        {%data = %+; do_that()}
}

Страницы

  • img

Об архиве

Эта страница содержит последние записи категории Язык.

Предыдущая категория — Фонд.

Следующая категория — Golf.

Смотрите новые записи на главной странице или загляните в архив, где есть ссылки на все сообщения.