Как я могу определить, существует ли (объявлена) в пакете лексическая переменная, даже если она не инициализирована? - PullRequest
2 голосов
/ 09 мая 2020

Допустим, у меня есть что-то

package Foo;
my $bar;

Как я могу определить, объявлен ли $bar, независимо от того, что он неинициализирован?

На каком-то уровне я предполагаю, что это возможно, потому что warnings знает это, здесь warnings знает, что переменная $bar существует, поэтому вы получите только неинициализированное предупреждение.

$ perl -wE'my $bar; print $bar;'
Use of uninitialized value $bar in print at -e line 1.

Но класс предупреждений once знает, что переменная $baz даже не объявлен.

$ perl -wE'my $bar; print $baz;'
Name "main::baz" used only once: possible typo at -e line 1.
Use of uninitialized value $baz in print at -e line 1.

Аналогично, strict просто остановит компиляцию, поэтому он тоже должен это знать (обратите внимание, что die никогда не срабатывает).

$ perl -wE'use strict; my $bar; print $baz; die 42;'
Global symbol "$baz" requires explicit package name (did you forget to declare "my $baz"?) at -e line 1.
Execution of -e aborted due to compilation errors.

Значит, он тоже должен это знать.

Ответы [ 4 ]

3 голосов
/ 10 мая 2020

PadWalker может проверить, какие лексические переменные были определены.

use PadWalker ':all';
my $foo;

my $level = -1;
while (my $pad = eval { peek_my(++$level) }) {
    print "$_ is declared in scope $level\n" for keys %$pad;
}

$level is defined in scope 0
$foo is defined in scope 0
2 голосов
/ 11 мая 2020
package Foo;
my $x;
my $eval_fmt = 'use strict; %s || 1';
eval( sprintf $eval_fmt, '$y' ) or warn 'No such variable: $y';
eval( sprintf $eval_fmt, '$x' ) and warn 'Variable $x exists';
2 голосов
/ 10 мая 2020

Для ясности, лексическая переменная не является частью какого-либо пакета и вообще не взаимодействует с системой пакетов; это совершенно другой бухгалтерия. Он принадлежит к области, в которой находится, независимо от объявления любого пакета. Эта область видимости - это либо заключающие скобки, либо объявленная подпрограмма, либо файл.

Большинство приведенных вами примеров (once и strict) имеют дело с переменными пакета. Для этого вы можете просто посмотреть в sta sh, чтобы узнать, определено ли имя.

Для неинициализированного случая perl видит, что переменная не имеет значения, когда пытается ее использовать.

2 голосов
/ 10 мая 2020

Без необходимости Padwalker (печатает "is lex" один раз):

package Foo;

print "is lex\n" if eval('\\$' . __PACKAGE__ . '::foo') != \$foo;
my $foo;
print "is lex\n" if eval('\\$' . __PACKAGE__ . '::foo') != \$foo;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...