perl - 为什么这个 Perl 变量保持它的值

标签 perl variables initialization declaration

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

最佳答案

首先,请注意 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;
    }
    

关于perl - 为什么这个 Perl 变量保持它的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17356168/

相关文章:

php - 无论如何,我可以通过 ajax 获取 PHP 数组的值吗?

objective-c - 传递给 View 的 IOS 值丢失或被遗忘

java - 使用java中的标准键初始化非静态 HashMap

perl - 在 Perl 中从 SSH 输出中去除颜色细节

css - 基于某些值生成 SCSS mixin?

c++ - 了解对象初始化

string - 如何将字符串列表拆分为 R 中的奇数和偶数元素

python - Apache 记分板(用于服务器统计)有 Python 接口(interface)吗?

perl - IO::Socket::SSL - 建立客户端连接

regex - 如何替换正则表达式匹配并在 Perl 中映射替换?