Thursday, November 4, 2010

5 способов создания констант в Perl


  1. Прагма constant. Позволяет объявлять константы на этапе компиляции:
    use constant PI => 4 * atan2(1, 1);

    Этот способ весьма эффективен, но имеет несколько недостатков.

    • Такие "константы" не могут быть интерполированы в строках, что часто неудобно.

    • При использовании ссылки в качестве константы, возможно изменение данных по ссылке:
      use constant ARRAY => [ 1,2,3,4 ];
      print ARRAY->[1];
      ARRAY->[1] = " be changed";
      print ARRAY->[1];


    • Могут возникать проблемы, если константа используется в качестве ключа хэша, e.g. $hash{CONSTANT}, или перед оператором =>. В таких случаях надо давать дополнительные подсказки компилятору, e.g. $hash{+CONSTANT}.

    • Константы являются глобальными для модуля, в котором они определены.

    • Наконец, они могут быть банально переопределены с помощью той же прагмы.



  2. Модуль Readonly.
    use Readonly;
    Readonly my $PI => 4 * atan2(1, 1);

    Данный способ лишен всех недостатков, связанных с прагмой constant. Readonly правильно работает со ссылками, делая все данные по ссылке неизменяемыми. Однако он гораздо медленнее, особенно если не установлен модуль Readonly::XS. По словам автора, разница в производительности по сравнению c constant примерно в 20 раз.

    Несмотря на это, именно Readonly чаще всего используется для создания констант в Perl.

  3. Модуль Const::Fast.
    use Const::Fast;
    const my $PI => 4 * atan2(1, 1);

    Этот модуль похож на Readonly. Вместо tie он использует внутренний флаг SV, что делает его гораздо более быстрым.

  4. Еще один способ создания неизменяемых скалярных переменных - присвоение ссылки на константное значение (число, литерал или выражение) переменной типа typeglob:
    our $PI;
    *PI = (4 * atan2 1, 1);
    $PI = 3.14; # Modification of a read-only value attempted at ..

    Этот способ работает только для глобальных переменных.

  5. Начиная с версии Perl 5.8, для создания констант можно использовать встроенную функцию Internals::SvREADONLY():
    my $PI = 4 * atan2 1, 1;
    Internals::SvREADONLY($PI => 1);
    $PI = 3.14; # Modification of a read-only value attempted at ..

    Именно эту функцию внутренне используют модули Const::Fast и Data::Lock.

No comments:

Post a Comment