Использование констант в Perl
я пытаюсь определить константы в Perl, используя constant
ПРАГМА:
use constant {
FOO => "bar",
BAR => "foo"
};
у меня небольшие неприятности, и я надеюсь, что есть стандартный способ справиться с этим.
прежде всего...
я определяю сценарий крючка для Subversion. Чтобы сделать вещи простыми, я хочу иметь один файл, где класс (пакет), который я использую, находится в том же файле, что и мой фактический скрипт.
большая часть этого пакета будет иметь константы, участвующие в это:
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 и быть максимально простым в работе.
4 ответов
если вы хотите сохранить все в одном файле, вы можете определить свой пакет констант следующим образом:
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.
на Perl константы не являются константами. Они определяются компиляцией как особый вид функции, которая встроена во время компиляции.
Я нахожу, что Perl "константы" больше боль, чтобы использовать, чем не использовать. Итак, обычно мой подход заключается в использовании скаляров со всеми прописными буквами.
my $PI = 3.14159;
.
Barewords автоматически цитируются, когда они появляются в хэш-поиске. Вам нужно заставить sub, который реализует константу, которая будет вызываться вместо этого:
$myHash{FOO} = 'bar'; # doesn't work, bareword quoted
$myHash{+FOO} = 'bar'; # okay
$myHash{&FOO} = 'bar'; # okay
$myHash{FOO()} = 'bar'; # okay
экспорт функций и переменных из одного пакета в другой-это все манипуляции с таблицей символов. The 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
.
Я второй Эрик Стром ответ.
однако, вот другой способ (но это слишком сильно раскрывает реализацию 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";