В Perl действительно ли возможно создать глобальную переменную на основе строки?
Например, если у меня была функция как:
sub create_glob_var {
my ($glob_var_str) = @_;
# something like this ( but not a hash access).
our ${$glob_var_str};
};
и я назвал его как:
create_glob_var( "bar" );
Как я мог изменить create_glob_var
на самом деле создать названную глобальную переменную $bar
?
Мой проект использует жемчуг 5.8.5.
Править
Следующее не работает:
use strict;
BEGIN {
sub create_glob_var {
my ($glob_var_str) = @_;
no strict 'refs';
$$glob_var_str = undef; # or whatever you want to set it to
}
create_glob_var("bah");
};
$bah = "blah";
Производит:
Variable "$bah" is not imported at /nfs/pdx/home/rbroger1/tmp2.pl line 12. Global symbol "$bah" requires explicit package name at /nfs/pdx/home/rbroger1/tmp2.pl line 12. Execution of /nfs/pdx/home/rbroger1/tmp2.pl aborted due to compilation errors.
ОБРАТИТЕ ВНИМАНИЕ, что я понимаю, что использование глобальных переменных вызывает истончение озонового слоя и мужское облысение. Я пытаюсь очистить некоторый унаследованный код, который уже полностью заражен использованием глобальных переменных. Каждый осуществляет рефакторинг за один раз...
Если вы пытаетесь очистить старый код, вы можете написать модуль, который экспортирует необходимые переменные. Каждый раз, когда вы чувствуете необходимость вызвать create_glob_var
, вместо этого добавьте переменную в этот пакет и поместите ее в список импорта.
Это поможет вам отслеживать, что происходит и как используются переменные.
package MyVars;
use strict; use warnings;
use Exporter 'import';
our($x, %y, @z);
our @EXPORT_OK = qw( $x %y @z );
Сценарий:
#!/usr/bin/perl
use strict;use warnings;
use MyVars qw( $x %y @z );
$x = 'test';
%y = (a => 1, b => 2);
@z = qw( a b c);
use Data::Dumper;
print Dumper \($x, %y, @z);
Вывод:
$VAR1 = \'test'; $VAR2 = { 'a' => 1, 'b' => 2 }; $VAR3 = [ 'a', 'b', 'c' ];
Попробуйте ответить на этот вопрос: Есть ли в Perl динамические переменные, подобные PHP?
Вкратце, это похоже на вы должны уметь делать $$ glob_var_str = "something";
Вам придется использовать eval
, но это обычно считается злом. Что-то вроде:
eval("$glob_var_str = \@_;");
EDIT
Только что проверил, что это можно сделать только без my
и с no strict refs
.
Прагма vars
уже делает тяжелую работу для того, что вы хотите, поэтому используйте ее:
#! /usr/bin/perl
use warnings;
use strict;
use vars;
BEGIN { vars->import(qw/ $bah /) }
$bah = "blah";
print $bah, "\n";
Если вы предпочитаете напишите create_glob_var
, затем используйте
#! /usr/bin/perl
use warnings;
use strict;
use vars;
sub create_glob_var { vars->import("\$$_[0]") }
BEGIN { create_glob_var "bah" }
$bah = "blah";
print $bah, "\n";
В любом случае, результат будет
blah
. Мне любопытно узнать, почему вы хотите сделать это таким образом, а не объявлять эти переменные с помощью нашего
. Да, может потребоваться несколько итераций, чтобы уловить их все, но в любом случае это краткосрочные исправления, не так ли?
В общем, вы можете использовать переменную в качестве имени переменной (см. «Символические ссылки» в perlref ), но вы действительно, действительно не хотите этого делать: включение прагмы strict 'refs'
отключает эту функцию.
Рафаэль Гарсиа-Суарес проявил большую мудрость, когда написал: «Я не знаю, в чем заключается ваша первоначальная проблема, но я предлагаю использовать хеш».
См. Также:
sub create_glob_var {
my ($glob_var_str) = @_;
no strict 'refs';
$$glob_var_str = undef; # or whatever you want to set it to
}
no strict 'refs'
необходимо только в том случае, если действует use strict
, что всегда должно быть быть.
Приложение:
Если вы спрашиваете, есть ли способ написать подпрограмму create_glob_var
, чтобы следующий код был успешным:
use strict;
create_glob_var("bar");
$bar = "whatever";
... тогда ответ - «Нет». Однако прагма Perl vars
сделает то, что вы хотите:
use strict;
use vars qw($bar);
$bar = "whatever";
Но это своего рода кодирование Perl в старом стиле. В настоящее время обычно можно поступить так:
use strict;
our $bar = "blah";
наш
может также просто объявлять глобальные переменные, которые можно свободно использовать позже:
our ($foo, @bar, %baz);
# ...
$foo = 5;
@bar = (1, 2, 3);
%baz = (this => 'that');
Ответ Sinan Ünür действительно лучший. Однако это пробудило мое любопытство, поэтому я немного почитал (perldoc perlmod) и узнал о хэше "имя_пакета::" как способе доступа к пространству имен пакета.
Следующий код добавляет запись в таблицу символов пакета main::
use strict;
my $name = "blah";
my $var = "sss";
$main::{$name} = \$var;
print "$main::blah\n";
Это выводит "sss".
Однако мне пришлось добавить имя пакета в оператор печати, потому что "use strict" все еще не обманывает. Я продолжу поиски - use vars, похоже, не работает в данный момент.