среда, 23 декабря 2009 г.

Форматирование даты и inline 'foreach'

Прочитал про велосипеды для форматирования даты. «Симпатичный» велосипед от sharifulin:

my $TODAY = join '.', map { $_->[3], $_->[4]+1, $_->[5]+1900} [localtime];

Как способ получения даты мне это выражение не нравится. Где что-то простое и идет работа с timestamp, я использую strftime, где нужно что-то более продвинутое — там я беру DateTime и невозбранно использую форматы.

Но как прием — интересно. Попробовал усовершенствовать:

my $TODAY = join '.', $_->[3], $_->[4]+1, $_->[5]+1900 for [localtime];

Не работает!

my $TODAY; $TODAY = join '.', $_->[3], $_->[4]+1, $_->[5]+1900 for [localtime];

Работает!

Кто может объяснить мне, что за нафиг?

P. S. А тем, кто все-таки предпочитает передвигаться на ходулях собственного изобретения, предлагаю заценить модуль Acme::Current.

15 comments:

  1. С for обычно использую в сабах, но там у меня return есть.

    Твой первый вариант не работает, т.к. ты в for'е создаешь локальную переменную, а в Perl 5 – это хак для создания статических переменных :) Посмотри на perlmonks это давно обсуждалось.
    ОтветитьУдалить
  2. Если бы она была локальная,

    perl -Mstrict -le 'my $var = $_ for 1; print $var'

    ругалось бы. inline-операторы не создают лексической области видимости. По крайней мере полноценной. А это фигня какая-то. Мне не нравится :)

    По каким словам искать-то?
    ОтветитьУдалить
  3. Я же говорю это хак или фича перла пятого, создание статической переменной. Слова попробуй static variable

    То же самое работает с постфиксным if. Причем именно в постфиксе!
    ОтветитьУдалить
  4. Ага. Вот оно самое: http://www.perlmonks.org/?node_id=647911

    Оказывается, в perlsyn еще можно кое-что почитать. Хотя, скорее всего, уже читал, просто забыл за ненадобностью.
    ОтветитьУдалить
  5. P. S. Делать статическую переменную и, вообще, основывать свой код на официально неопределенном поведении я бы никогда не стал (разве только если на состязании по obfuscated Perl). Для создания статических переменных никто не отменял замыкания (closures). А все такие хаки - от лукавого.
    ОтветитьУдалить
  6. Не работает потому что вместо '=' в примере - '.='
    ОтветитьУдалить
  7. Спасибо, исправил (не вычистил после экспериментов). Однако относительно работоспособности совершенно монопенисуально: что '=', что '.='
    ОтветитьУдалить
  8. Sharifulin правильно написал почему не работает первый пример, в нём получается что лексическая переменная создаётся в цикле, ей присваивается значение и после выхода из цикла она освобождается, вот пример и не работает. Если объявить её глобальной например (our) она работать будет, так что никакой мистики.
    ОтветитьУдалить
  9. > лексическая переменная создаётся в цикле
    > так что никакой мистики

    Да ну? А как вот это понимать?

    perl -le 'for (0..4) { my $i for (); print ++$i }'
    ОтветитьУдалить
  10. Вообще-то с предыдущим это неравнозначные примеры, а понимать это надо как оптимизацию пустых циклов, если во внутренний цикл добавить значения, то пример работает как надо.
    ОтветитьУдалить
  11. И вообще объявлять лексическую переменную в цикле однострочном - как-то странно
    ОтветитьУдалить
  12. > понимать это надо как оптимизацию пустых циклов

    Да ну? Где же тут оптимизируется?

    $ perl -MO=Deparse -e 'for (0..4) { my $i for (); print ++$i }'
    foreach $_ (0 .. 4) {
    my $i foreach (());
    print ++$i;
    }

    > объявлять лексическую переменную в цикле однострочном - как-то странно

    for в Perl — больше чем for. Это еще и with. Так что не странно. Странен результат. К тому же это работает со всеми inline операторами, как было выше упомянуто.
    ОтветитьУдалить
  13. хмммм... я мысль понял, по-видимому это - баг, поздравляю!!! =)
    ОтветитьУдалить
  14. > по-видимому это - баг

    Что задокументировано - то не баг ;-)

    perldoc perlsyn

    > NOTE: The behaviour of a "my" statement modified with a statement modifier conditional or loop construct (e.g. "my
    > $x if ...") is undefined. The value of the "my" variable may be "undef", any previously assigned value, or
    > possibly anything else. Don't rely on it. Future versions of perl might do something different from the version
    > of perl you try it out on. Here be dragons.
    ОтветитьУдалить