perl-for循环不会修改`my`变量,但是修改`我们的’变量

前端之家收集整理的这篇文章主要介绍了perl-for循环不会修改`my`变量,但是修改`我们的’变量前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在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子程序不能嵌套(并且始终具有模块范围),因此它们似乎无法关闭我的变量.看来,在这种情况下,严格模式下的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.

即它应该拒绝子例程,因为自由变量没有被声明为任何地方,而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.

换句话说,循环迭代器总是被定位到循环中.如果它是全局的,那么它的行为就像在循环块中被声明为本地的.如果它是一个词汇,那么它的行为就像它在循环块中被声明的那样.

将这个应用于您的两个示例将有助于了解发生了什么.

our $x;

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

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

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

当其范围结束时恢复旧值.如果在for循环之后添加print $x,可以看到这一点.

use v5.10;

our $x = 42;

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

say $x;  # 42

我们来看看你的代码涉及到词汇(我的变量).

my $x;

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

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

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

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

这里有一些风格的外卖.

始终将参数传递到您的函数中.

实际上,print_func应该有一个参数.那么你不用担心复杂的范围规则.

sub print_func {
    my $arg = shift;
    print "$arg\n";
}

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

总是用于我的$x.

不要依赖于复杂的隐式for循环范围规则.总是用我的声明循环迭代器.

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和大多数现代语言没有这样的限制.

如果您一次性声明您的变量,就很难知道它们的内容,很难知道使用或影响的变量.如果你声明它接近于它的第一次使用,限制什么可以影响它,并使它更明显它是什么.

原文链接:https://www.f2er.com/Perl/172481.html

猜你在找的Perl相关文章