gpt4 book ai didi

perl - for 循环不会修改 `my` 变量,但会修改 `our` 变量

转载 作者:行者123 更新时间:2023-12-03 23:35:15 29 4
gpt4 key购买 nike

在 Perl 5.20 中,for 循环似乎能够修改模块作用域的变量,但不能修改父作用域中的词法变量。

#!/usr/bin/env perl
use strict;
use warnings;

our $x;

sub print_func {
print "$x\n";
}

for $x (1 .. 10) {
print_func;
}

像您期望的那样打印 1 到 10,但以下内容不会:
#!/usr/bin/env perl
use strict;
use warnings;

my $x;

sub print_func {
print "$x\n";
}

for $x (1 .. 10) {
print_func;
}

发出以下警告 10 次:
Use of uninitialized value $x in concatenation (.) or string at perl-scoping.pl line 8.

这里发生了什么?我知道 perl 子例程不能嵌套(并且始终具有模块范围),因此它们无法关闭 my 似乎是合乎逻辑的。变量。似乎在那种情况下, strict 中的 perl模式应该拒绝第二个程序,并显示如下消息:
Global symbol "$x" requires explicit package name at perl-scoping.pl line 6.
Global symbol "$x" requires explicit package name at perl-scoping.pl line 9.

IE。它应该拒绝子程序,因为自由变量没有在任何地方声明,而 for 循环因为变量没有被声明。

为什么 Perl 会这样?

最佳答案

这是令人困惑但记录在案的行为,可能源于将循环迭代器变量设为隐式本地化全局而不是词法的错误决定。来自 Foreach Loops in perlsyn .

If the variable is preceded with the keyword my, then it is lexically scoped, and is therefore visible only within the loop. Otherwise, the variable is implicitly local to the loop and regains its former value upon exiting the loop. If the variable was previously declared with my, it uses that variable instead of the global one, but it's still localized to the loop.



换句话说, 循环迭代器始终定位于循环 .如果它是一个全局的,那么它的行为就像它已被声明 local在循环 block 内。如果它是一个词法,那么它的行为就像是用 my 声明的一样。在循环 block 内。

将此应用于您的两个示例将有助于理解发生了什么。
our $x;

sub print_func {
print "$x\n";
}

for $x (1 .. 10) {
print_func;
}

有一个隐含的 local $x在那个循环上。 local 真的应该被命名为 temp .它在其范围内临时覆盖全局变量的值,但它仍然是全局变量。这就是为什么 print_func可以看到。

旧值在其作用域结束时恢复。如果您添加 print $x,您可以看到这一点在 for 循环之后。
use v5.10;

our $x = 42;

for $x (1 .. 10) {
say $x;
}

say $x; # 42

让我们看看您的涉及词法( my 变量)的代码。
my $x;

sub print_func {
print "$x\n";
}

for $x (1 .. 10) {
print_func;
}

这里真正发生的是你有两个词法变量都称为 $x .一种是文件范围,一种是循环范围。内 $x在 for 循环上优先于外部 $x .这被称为“阴影”。

词汇不能在其物理范围之外被看到。 print_func()只看到外部未初始化的 $x .

从这里有一些风格上的收获。

始终将参数传递给您的函数。

实际上, print_func应该拿一个论据。然后您不必担心复杂的范围规则。
sub print_func {
my $arg = shift;
print "$arg\n";
}

for $x (1..10) {
print_func($x);
}

始终使用 for my $x .

不要依赖复杂的隐式 for循环范围规则。总是用 my 声明循环迭代器.
for my $x (1..10) {
print_func($x);
}

避免全局变量。

由于很难分辨出什么在访问全局,所以不要使用它们。如果您认为需要全局,请编写一个函数来控制对文件范围词法的访问。
my $Thing = 42;
sub get_thing { return $Thing }
sub set_thing { $Thing = shift; return }

将变量声明在靠近它们使用的位置。

Ye olde 编码风格会做一些事情,比如在文件或函数的顶部声明它们的所有变量。这是对非常、非常、非常古老的语言的保留,这些语言要求仅在某些地方声明变量。 Perl 和大多数现代语言没有这样的限制。

如果您一次声明所有变量,则很难知道它们的用途,也很难知道什么在使用或影响它。如果您将其声明为接近其首次使用,则会限制可能影响它的内容,并使其更明显其用途。

关于perl - for 循环不会修改 `my` 变量,但会修改 `our` 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36993801/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com