Я пытаюсь определить константы в Perl с помощью constant
прагма:
use constant {
FOO => "bar",
BAR => "foo"
};
Я сталкиваюсь с небольшим количеством проблемы и надеюсь, что существует стандартный способ обработать ее.
В первую очередь...
Я определяю сценарий рычага для Подверсии. Для создания вещей простыми я хочу иметь единственный файл, где класс (пакет), который я использую, находится в том же файле как мой фактический сценарий.
Большей части этого пакета вовлекут константы в него:
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 и быть максимально простым работать.
Если вы хотите сохранить все в одном файле, вы можете определить свой пакет констант следующим образом:
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';
часть использования
перестанет работать.
Константы Perl не являются константами. Они определены при компиляции как особый вид функции, которая встроена во время компиляции.
Я считаю, что использование «констант» Perl - это больше проблема, чем не использовать. Итак, обычно мой подход заключается в использовании скаляров со всеми прописными буквами. мой $ PI = 3,14159;
.
Я второй ответ Эрика Строма.
Однако есть другой способ (но он слишком сильно раскрывает реализацию 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";
Открытые слова автоматически заключаются в кавычки, когда они появляются при поиске по хешу. Вместо этого вам нужно принудительно вызвать подпрограмму, реализующую константу:
$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 }
в пакете MyClass
.