2

以下两个 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. 在这种情况下,它是如何首先声明的?

4

2 回答 2

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实际上做了以下事情:

  • 它在编译时声明一个符号。
  • 它在编译时创建变量[1]
  • 它在堆栈上放置一个指令,当范围退出时,该指令将清除[2]变量。
  • 它在执行时返回新变量。

因此,只创建了一个变量[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;
}

笔记:

  1. “变量”可能意味着几件事。我不确定这里哪个定义是准确的,但这没关系。

  2. 如果除了 sub 本身之外的任何东西都包含对变量的引用 (REFCNT>1) 或者如果变量包含一个对象,则该指令用一个新的变量替换该变量(在范围退出时)而不是清除现有的变量。这允许以下内容正常工作:

    my @a;
    for (...) {
        my $x = ...;
        push @a, \$x;
    }
    
于 2013-06-28T04:12:07.597 回答
-1

请参阅 ikegami 的更好答案,可能在上面。

在第一个示例中,由于条件,您永远不会在循环内定义 $foo,因此当您使用它时,您正在引用然后将值分配给隐式声明的全局变量。然后,第二次通过已经定义外部变量的循环。

在第二个示例中,每次执行块时都会在块内定义 $baz。所以第二次通过循环它是一个新的,尚未定义的局部变量。

于 2013-06-28T02:17:36.140 回答