В Perl: есть ли способ узнать имя переменной в списке?

Есть ли способ узнать имя переменной в этой ситуации без использования символических ссылок?

use strict;
...
for ($var1, $var2, $var3)
{
   die "NAME_OF_VAR is not defined" if !defined $_;
}

Вывод, если переменная не определена:

"var[123] не определен в..."


person Nuncio    schedule 06.05.2012    source источник
comment
Сомневаюсь (что бы это значило, если бы вы могли это сделать и список был for ($var1, undef, $var2) {...). Но было много раз, когда я не думал, что что-то можно сделать на Perl, и я ошибался.   -  person mob    schedule 06.05.2012


Ответы (5)


use strict;
use warnings;

my ($var1, $var2, $var3) = 1..2;
for( qw($var1 $var2 $var3) ) { print "$_ is undefined\n" if !defined eval($_) }

Строка my заимствована из примера TLP и имеет следующий вывод:

$var3 is undefined
person Kenosis    schedule 06.05.2012

Вот один из способов получить фатальное предупреждение о неопределенной переменной:

my ($var1, $var2, $var3) = 1..2;

{
    use warnings FATAL => 'all';
    my $test = "$var1 $var2 $var3";
}

Вывод:

Скрипт умирает, когда в блоке выше возникает ошибка. В этом случае:

Use of uninitialized value $var3 in concatenation (.) or string at ...

Я выбрал конкатенацию в качестве проверки определенности, но это может быть любая операция, вызывающая предупреждение при использовании неопределенных переменных.

person TLP    schedule 06.05.2012

PadWalker — это ответ на распутывание псевдонимов. Однако почти в любой ситуации, когда PadWalker является ответом, он может быть ответом на неправильный вопрос. Это один из тех модулей, которые используются либо для отладки, либо для поиска выхода после того, как загнали себя в угол. Если он используется как выход из плохого дизайна, возможно, лучше пересмотреть дизайн. В вашем случае ответ, наверное, тот, что уже упоминался: повышение уровня предупреждения до отказа.

Тем не менее, модуль существует, работает и с ним интересно играть.

Поскольку вопрос конкретно задавался о расшифровке или проверке псевдонимов, вот два примера, где PadWalker может сократить псевдоним до исходной переменной:

use strict;
use warnings;


use PadWalker qw( var_name );


my( $var1, $var2, $var3 ) = ( undef, undef, undef );


for ($var1, $var2, $var3) {
    warn var_name( 0, \$_ ) . ' is not defined in "for" loop'
        if !defined $_;
}


sub foo {
    warn var_name( 1, \$_[0] ) . ' is not defined in sub foo()'
        if !defined $_[0];
}

foo( $var1 );

Вывод, который дает, будет примерно таким:

$var1 is not defined in "for" loop at mytest.pl line 13.
$var2 is not defined in "for" loop at mytest.pl line 13.
$var3 is not defined in "for" loop at mytest.pl line 13.
$var1 is not defined in sub foo() at mytest.pl line 19.

Обратите внимание, как необходимо указать var_name( 0, ... внутри цикла for, тогда как внутри подпрограммы нам нужно вернуться на один дополнительный уровень, используя varname( 1, ....

Также, возможно, интересно то, что операторы given/when не используют псевдонимы, хотя они и создают видимость этого. Следовательно, PadWalker не может отследить переменную, указанную в given(...).

person DavidO    schedule 06.05.2012

Я думаю, вы сами сказали, что вам нужны символические ссылки. Помните, что это не зло, просто обычно это не то, что вам нужно. В этом конкретном случае вы выполняете своего рода метапрограммирование, вам важно имя переменной. Поэтому вы можете это сделать.

use strict;
...
for (qw/var1 var2 var3/)
{
   no strict 'refs';
   die "$_ is not defined" if !defined ${$_};
}
person Joel Berger    schedule 06.05.2012

Рассмотрим модуль PadWalker:

#!/usr/bin/env perl
use warnings;
use strict;

use PadWalker qw(var_name);

my $foo = 123;
print var_name(0, \$foo), "\n"; # prints "$foo"

PadWalker не установлен по умолчанию, поэтому вам нужно будет установить его с помощью инструмента командной строки cpan в вашей системе.

Конечно, PadWalker сумасшедший и, вероятно, не лучший способ делать то, что вы пытаетесь сделать, но время от времени с ним, безусловно, весело.

person Muir    schedule 06.05.2012