问题 参数的意外自动更新


显然我的理解了 没有自动化 pragma是不完美的,因为以下脚本的非线性19行为对我来说是非常令人惊讶的。

use 5.014;
use strict;
use warnings;
no autovivification qw(fetch exists delete warn);

{
  my $foo = undef;
  my $thing = $foo->{bar};

  # this does not die, as expected
  die if defined $foo;
}

{
  my $foo = undef;
  do_nothing( $foo->{bar} );

  # I would expect this to die, but it doesn't
  die unless defined $foo;
}

sub do_nothing {
  return undef;
}

运行脚本会产生:

Reference was vivified at test.pl line 8.

问题是:为什么 $foo 自动化时 $foo->{bar} 作为sub的参数提供,即使 no autovivification 有效吗?


12171
2018-03-08 09:57


起源

你安装了吗?也许加 warn 到不成熟的名单。那就是 no autovivification qw<fetch exists delete warn>; 当文档说出来时,看看是否有警告。 - simbabque
它已安装,否则脚本将在第11行死亡。我已使用添加结果更新了问题 warn。 - ryanm
这并不奇怪。 Perl并不是真的知道这一点 do_nothing 什么都不做,因为你给它一个参数,它必须自动生成它,以便你可以在sub中使用它。特别是,它不知道你是否做了一个矫揉造作 $_[0] 或不在 do_nothing。 - Dada
这就说得通了。感觉就像在文档中可以更明确的东西,因为对于任何来自传值语言的人来说都会令人惊讶。 - ryanm
它如何在一个sub(它是一个。)中有一个关键的区别 左值 上下文,对象必须是可修改的)。我觉得 这个答案 可以解释一下。 - zdim


答案:


在子例程调用中,函数的参数是别名 @_,所以必须可以修改它们。这提供了一个 左值 上下文,什么会触发autovivification。

当我们查看您使用的功能的描述时 自动激活,他们涵盖:

  • 'fetch'   - “rvalue dereferencing expressions”
  • 'exists'  - “取消引用属于某个部分的表达式 存在
  • 'delete'  - “取消引用属于某个部分的表达式 删除

这些都不涉及左值(也没有 warn)。

要在子程序调用中停止自动更新,您还需要添加 store

关闭左值解除引用表达式的自动生成,例如:[...]

docs继续举例,包括子程序调用。

当我将它添加到您的代码中时

no autovivification qw(fetch exists delete warn store);
# ...

我明白了

参考文献在noautoviv.pl第8行发生了变化。
参考文献在noautoviv.pl第16行发生了变化。
死于noautoviv.pl第19行。

10
2018-03-08 10:44