以下两个Perl变量声明有什么区别?
my $foo = 'bar' if 0;
my $baz;
$baz = 'qux' if 0;
当它们出现在循环的顶部时,差异很大。例如:
use warnings;
use strict;
foreach my $n (0,1){
my $foo = 'bar' if 0;
print defined $foo ? "defined\n" : "undefined\n";
$foo = 'bar';
print defined $foo ? "defined\n" : "undefined\n";
}
print "==\n";
foreach my $m (0,1){
my $baz;
$baz = 'qux' if 0;
print defined $baz ? "defined\n" : "undefined\n";
$baz = 'qux';
print defined $baz ? "defined\n" : "undefined\n";
}
结果
undefined
defined
defined
defined
==
undefined
defined
undefined
defined
似乎if 0
失败,因此foo
永远不会重新初始化为undef
。在这种情况下,它是如何首先声明的?
答案 0 :(得分:12)
首先,请注意my $foo = 'bar' if 0;
被记录为未定义的行为,这意味着它可以执行任何操作,包括崩溃。但我会解释无论如何会发生什么。
my $x
有三种记录效果:
简而言之,它假设像Java Scalar x = new Scalar();
,除非它在表达式中使用时返回变量。
但如果它实际上以这种方式工作,则以下将创建100个变量:
for (1..100) {
my $x = rand();
print "$x\n";
}
这意味着仅my
每次循环迭代就有两次或三次内存分配!非常昂贵的前景。相反,Perl只创建一个变量并在范围的末尾清除它。所以实际上,my $x
实际上做了以下事情:
因此,只创建了一个变量 [2] 。这比在每次输入范围时创建一个CPU更有效率。
现在考虑如果有条件地执行my
,或者根本不执行会发生什么。通过这样做,您将阻止它放置指令以清除堆栈上的变量,因此变量永远不会丢失其值。显然,这并不意味着发生,所以这就是为什么不允许my ... if ...;
。
有些人利用如下实施:
sub foo {
my $state if 0;
$state = 5 if !defined($state);
print "$state\n";
++$state;
}
foo(); # 5
foo(); # 6
foo(); # 7
但这样做需要忽略禁止它的文档。使用
可以安全地实现上述目标{
my $state = 5;
sub foo {
print "$state\n";
++$state;
}
}
或
use feature qw( state ); # Or: use 5.010;
sub foo {
state $state = 5;
print "$state\n";
++$state;
}
注意:
“变量”可能意味着一些事情。我不确定这里的定义是否准确,但没关系。
如果除了子本身之外的任何内容都包含对变量的引用(REFCNT> 1)或者变量包含一个对象,则该指令将该变量替换为一个新的(在作用域出口上)而不是清除现有的变量。这允许以下内容按预期工作:
my @a;
for (...) {
my $x = ...;
push @a, \$x;
}
答案 1 :(得分:-1)
请参阅ikegami的更好答案,可能在上面。
在第一个例子中,由于条件的原因,你永远不会在循环中定义$ foo,因此当你使用它时,你会引用然后为隐式声明的全局变量赋值。然后,第二次通过循环已经定义了外部变量。
在第二个示例中,每次执行块时,都会在块内定义$ baz。所以第二次通过循环它是一个新的,尚未定义的局部变量。