Как проверить, объявлена ​​ли переменная в perl? - PullRequest
8 голосов
/ 21 августа 2010

Я использую use strict; в Perl, и с этим я использую следующее утверждение.

unless(defined($x)){
      print "Not defined";
}

Где $ x нигде не объявлен. Поэтому я ожидаю, что он напечатает "Not defined", но он возвращает ошибку

Global symbol "$x" requires explicit package name at *********** in line 15.

Ответы [ 7 ]

18 голосов
/ 21 августа 2010

Прагма strict состоит из трех частей: строгие ссылки, строгие переменные и строгие подпрограммы.Вы сталкиваетесь с

строгие переменные

. Это генерирует ошибку времени компиляции, если вы обращаетесь к переменной, которая не была объявлена ​​с помощью our или use varsлокализован через my или не был полностью квалифицирован.Поскольку это делается для того, чтобы избежать проблем с самоубийствами и тонких проблем с динамической областью действия, просто local переменная недостаточно хороша.

Поскольку он генерирует ошибки во время компиляции, ваш не-BEGIN код даже не будет иметь возможности для запуска.Вы можете временно разрешить не строгие переменные внутри блока, как в

{
  no strict 'vars';
  print "Not defined!\n" unless defined $x;
}

, но обратите внимание, что оператор Perl defined сообщает вам, определено ли значение, а не было ли объявлено переменное.

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

5 голосов
/ 22 августа 2010

Я думаю, что вы смешиваете «определенные» и «объявленные» концепции.

Вы спрашиваете «Как проверить, объявлена ​​ли переменная в perl», но затем вы проверяете, определена ли переменная. Это две разные концепции.

В perl, если вы используете 'используйте строгий' , вы автоматически проверяете наличие любой переменной , не объявленной (используя my , local или наш ). После того, как вы объявили переменную, вы можете проверить, определена ли она (назначено ли значение).

Таким образом, в вашем тесте вы пропускаете предварительную декларацию перед проверкой на определенность

use strict;
my $x;  # you are missing this part
[...] | # code
# your test for define
print defined $x? "defined\n" : "not defined\n";

Обратите внимание, что тестирование всего за $ x неверно для вашей цели:

my ($x,$y, $z);
$w;         # not declared (use strict will catch it and die)
$x = 0;     # declared and defined BUT if you make a logic test like 'if ($x) {}' then it will be FALSE, so don't confuse testing for **'$x'** and testing for **'defined $x'**
$y = undef; # declared but not defined
$z = 1;     # declared, defined, and logial test TRUE

Наконец, ответ на ксеноррацицид кажется мне ошибочным: он предлагает 'если $ x' не является правильным для тестирования, если оно определено, как я уже говорил. Он также предлагает ', если не существует $ x', что неправильно для проверки скаляров . Тест «существует» предназначен только для ключей хеширования (и не рекомендуется для массивов).

Надеюсь, это поможет.

5 голосов
/ 21 августа 2010

Вы даже не можете ссылаться на переменную, если она не объявлена. Когда вы спрашиваете

defined( $x ) ?

компилятор будет жаловаться: я не знаю, о чем вы спрашиваете, как я могу сказать, что он определен? Он не имеет ссылки на эту переменную, поскольку вы указали, что не хотите, чтобы переменные создавались автоматически по имени.

Если бы strict 'vars' не было включено - что по умолчанию используется при use strict - тогда это создаст запись в таблице символов пакета для 'x'.

Интересно, что без strict 'refs' также легко проверить, находится ли переменная в таблице символов пакета.

defined( *{ __PACKAGE__ . '::x' }{SCALAR} )

Поскольку нет способа автоматически создать лексику («мои переменные»), также нет стандартного способа проверить, объявлены ли лексики. Лексические переменные хранятся в «блокноте». Но есть модуль PadWalker, который может помочь.

Чтобы проверить текущий уровень, вы можете получить хэш пэда, а затем проверить, существует ли он в текущем паде. Вы также можете вернуться назад через стек (целочисленный аргумент работает примерно как caller), чтобы найти, где был самый последний x.

my $h = peek_my (0);
exists $h->{x};
1 голос
/ 06 ноября 2012

Обычно этот вид кода не требуется для серьезной программы, но все же, почему бы не просто ради интереса: (при условии строгого использования)

print "Not defined\n" unless eval 'ref(\$x)';
1 голос
/ 21 августа 2010
 #
 print "Not defined" if !defined($x);

результат будет

Не определено

 #
 use strict;
 print "Not defined" if !defined($x);

приведет к ошибке, как в вашем вопросе.

Смотрите: http://perldoc.perl.org/strict.html, гдеописано, как вы можете импортировать только необходимые ограничения.(Однако использовать строгое «vars» очень хорошая идея :))

0 голосов
/ 16 мая 2013

Мое решение - #! / Usr / bin / perl -l

use strict;

# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'

our $lol = eval {$lol} || 'lol' ;

print $lol;
0 голосов
/ 16 мая 2013
#!/usr/bin/perl -l

use strict;

# if string below commented out, prints 'lol' , if the string enabled, prints 'eeeeeeeee'
#my $lol = 'eeeeeeeeeee' ;
# no errors or warnings at any case, despite of 'strict'

our $lol = eval {$lol} || 'lol' ;

print $lol;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...