Использование констант в Perl
Я пытаюсь определить константы в Perl с помощью constant
прагмы:
use constant {
FOO => "bar",
BAR => "foo"
};
У меня возникают проблемы, и я надеюсь, что там будет стандартный способ обработки.
Прежде всего...
Я определяю крючок script для Subversion. Чтобы сделать все просто, я хочу иметь один файл, в котором я использую класс (пакет), в том же файле, что и мой фактический script.
Большая часть этого пакета будет содержать константы:
print "This is my program";
package MyClass;
use constant {
FOO => "bar"
};
sub new { ... }
Я хочу, чтобы моя константа FOO
была доступна моей основной программе. Я хотел бы сделать это, не обращаясь к нему как MyClass::FOO
. Обычно, когда пакет представляет собой отдельный файл, я мог бы сделать это в своей основной программе:
use MyClass qw(FOO);
но поскольку мой класс и программа являются одним файлом, я не могу этого сделать. Что было бы лучшим способом для моей основной программы иметь доступ к моим константам, определенным в моем классе?
Вторая проблема...
Я хотел бы использовать константные значения в качестве хеш-ключей:
$myHash{FOO} = "bar";
Проблема заключается в том, что %myHash
имеет буквальную строку FOO
как ключ, а не значение константы. Это вызывает проблемы, когда я делаю такие вещи:
if (defined $myHash{FOO}) {
print "Key " . FOO . " does exist!\n";
}
Я могу заставить контекст:
if (defined $myHash{"" . FOO . ""}) {
Я мог бы добавить круглые скобки:
if (defined $myHash{FOO()}) {
Или, я мог бы использовать временную переменную:
my $foo = FOO;
if (defined $myHash{$foo}) {
Ни один из них не является действительно хорошим способом решения этой проблемы. Итак, что является лучшим способом? Есть один способ, которым я не хватает?
Кстати, я не хочу использовать Readonly::Scalar
, потому что это 1). медленно, и 2). не входит в стандартный пакет Perl. Я хочу определить, что мой крючок не требует дополнительных пакетов Perl и как можно проще работать.
Ответы
Ответ 1
Если вы хотите сохранить все в одном файле, вы можете определить свой пакет констант следующим образом:
use warnings;
use strict;
BEGIN { # BEGIN means this will all happen at compile time
package Constants;
$INC{'Constants.pm'}++; # tell `require` that the package is loaded
use base 'Exporter'; # setup package to export
our @EXPORT_OK = qw( PI ); # what to export
use constant PI => 3.14159; # define your constant
}
package main;
use Constants qw( PI ); # use it like normal
print PI;
Затем, чтобы обмануть индексы автохвоста внутри хэша, вы можете записать его так: $hash{+PI}
или $hash{(PI)}
или $hash{PI()}
или $hash{&PI}
или $hash{::PI}
... Возможно, я мог продолжать идти, но Я думаю, вы понимаете.
Причина, по которой требуется $INC{'Constants.pm'}++
, состоит в том, что строка use Constants qw( PI );
действительно означает:
BEGIN {
require 'Constants.pm';
Constants->import( qw( PI ) );
}
И require
проверит %INC
, чтобы узнать, был ли пакет уже загружен. Поэтому, давая ему истинное значение (в этом случае 1), часть require 'Constants.pm';
use
станет no-op.
Ответ 2
-
Perl-константы не являются константами. Они определяются компиляцией как особый вид функции, которая встроена во время компиляции.
-
Я нахожу, что константы Perl более больны, чем использовать. Поэтому, как правило, мой подход заключается в использовании скаляров со всеми прописными буквами. my $PI = 3.14159;
.
Ответ 3
Базы автоматически цитируются, когда они появляются в поиске хэша. Вам нужно принудительно включить sub, который реализует константу, которая будет вызываться вместо:
$myHash{FOO} = 'bar'; # doesn't work, bareword quoted
$myHash{+FOO} = 'bar'; # okay
$myHash{&FOO} = 'bar'; # okay
$myHash{FOO()} = 'bar'; # okay
Экспорт функций и переменных из одного пакета в другой - все манипуляции с таблицами символов. Модуль Exporter
делает это легко для нас, но это не так сложно сделать без модуля.
package main;
sub stuff { return &FOO x 3 }
*FOO = *MyClass::FOO;
print stuff(); # "barbarbar"
package MyClass;
use constant FOO => "bar";
Вы также могли бы сказать
BEGIN { *main::FOO = *FOO }
под package MyClass
.
Ответ 4
Второй ответ Эрика Строма.
Однако, это другой способ (но это слишком много для реализации Perl):
use strict;
use warnings;
package Constants;
sub FOO() { 'bar' }
sub BAR() { 'foo' }
sub main::FOO() { FOO }
sub main::BAR() { BAR }
package main;
print FOO, BAR, "\n";