为什么此Perl变量保持其值 [英] Why does this Perl variable keep its value

查看:76
本文介绍了为什么此Perl变量保持其值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下两个Perl变量声明之间有什么区别?

What is the difference between the following two Perl variable declarations?

my $foo = 'bar' if 0;

my $baz;
$baz = 'qux' if 0;

当它们出现在循环的顶部时,区别是很明显的.例如:

The difference is significant when these appear at the top of a loop. For example:

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

It seems that if 0 fails, so foo is never reinitialized to undef. In this case, how does it get declared in the first place?

推荐答案

首先,请注意,my $foo = 'bar' if 0;被记录为未定义的行为,这意味着它可以执行任何操作,包括崩溃.但是我还是会解释会发生什么.

First, note that my $foo = 'bar' if 0; is documented to be undefined behaviour, meaning it's allowed to do anything including crash. But I'll explain what happens anyway.

my $x具有三个已记录的效果:

my $x has three documented effects:

  • 它在编译时声明一个符号.
  • 它会在执行时创建一个新变量.
  • 它在执行时返回新变量.

简而言之,它类似于Java的Scalar x = new Scalar();,只是它在表达式中使用时会返回变量.

In short, it's suppose to be like Java's Scalar x = new Scalar();, except it returns the variable if used in an expression.

但是,如果它确实以这种方式工作,则以下代码将创建100个变量:

But if it actually worked that way, the following would create 100 variables:

for (1..100) {
   my $x = rand();
   print "$x\n";
}

这意味着对于my,每个循环迭代有两到三个内存分配!一个非常昂贵的前景.取而代之的是,Perl仅创建一个变量,并在作用域末尾将其清除.因此,实际上,my $x实际上会执行以下操作:

This would mean two or three memory allocations per loop iteration for the my alone! A very expensive prospect. Instead, Perl only creates one variable and clears it at the end of the scope. So in reality, my $x actually does the following:

  • 它在编译时声明一个符号.
  • 它在编译时创建变量 [1] .
  • 它在堆栈上放置了一条指令,该指令将在退出作用域时清除 [2] 变量.
  • 它在执行时返回新变量.
  • It declares a symbol at compile-time.
  • It creates the variable at compile-time[1].
  • It puts a directive on the stack that will clear[2] the variable when the scope is exited.
  • It returns the new variable on execution.

如此,将仅创建一个变量 [2] .与每次输入范围时创建一个CPU相比,这比CPU效率要高得多.

As such, only one variable is ever created[2]. This is much more CPU-efficient than then creating one every time the scope is entered.

现在考虑如果有条件地执行my或根本不执行my会发生什么.这样,可以防止它放置指令以清除堆栈上的变量,因此该变量永远不会丢失其值.显然,这并不意味着要发生,这就是为什么不允许my ... if ...;的原因.

Now consider what happens if you execute a my conditionally, or never at all. By doing so, you are preventing it from placing the directive to clear the variable on the stack, so the variable never loses its value. Obviously, that's not meant to happen, so that's why my ... if ...; isn't allowed.

有些人可以利用以下实现方式:

Some take advantage of the implementation as follows:

sub foo {
   my $state if 0;
   $state = 5 if !defined($state);
   print "$state\n";
   ++$state;
}

foo();  # 5
foo();  # 6
foo();  # 7

但是这样做需要忽略禁止它的文档.可以使用

But doing so requires ignoring the documentation forbidding it. The above can be achieved safely using

{
   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;
}


注意:


Notes:

  1. 变量"可能意味着两件事.我不确定此处的定义是否正确,但这无关紧要.

  1. "Variable" can mean a couple of things. I'm not sure which definition is accurate here, but it doesn't matter.

如果子元素本身以外的任何东西都持有对该变量的引用(REFCNT> 1),或者如果变量包含一个对象,则该指令将变量替换为新变量(在作用域退出时),而不是清除现有变量.这样可以使以下各项正常工作:

If anything but the sub itself holds a reference to the variable (REFCNT>1) or if variable contains an object, the directive replaces the variable with a new one (on scope exit) instead of clearing the existing one. This allows the following to work as it should:

my @a;
for (...) {
    my $x = ...;
    push @a, \$x;
}

这篇关于为什么此Perl变量保持其值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆