在原始的、未缓解的 Perl 中,变量在范围内是全局的。也就是说,它们存在于您的程序中,从您定义它们的位置到脚本的末尾。此外,在 Perl 中,当您将变量与未定义的值一起使用时,它们就会出现。在字符串中,这被视为空字符串。在数字中,它被视为零。
因此,在子程序中,如果您在主程序中定义了一个变量,那么它也会在您的子程序中定义:
$foo = "Hello";
call_sub();
sub call_sub {
print "$foo\n";
}
这将打印“Hello”。
但是,任何人都不应该在这种模式下使用 Perl,因为它很容易出错:
$name = "Bob"
print "Hello $Name!\n";
哎呀!我定义它时使用了$name,使用它时使用了$Name。另外,您不想要这样的全局变量。否则,您的子程序可能会覆盖您的主程序变量。让编写大型复杂程序变得非常非常困难。
为了解决这个问题,强烈建议您在代码中加入这两行代码:
use strict;
use warnings;
use warnings; 将发出各种各样的警告,例如将未初始化的变量视为字符串和数字。
use strict; 做出了更大的改变。简单地说(而且不正确),use strict 强制您在使用变量之前声明变量。
use warnings;
use strict;
my $name = "Bob"
print "Hello $Name\n";
该程序无法运行,因为从未声明过 $Name(您使用 my 关键字声明变量)。您可以看到这将如何防止错误。
然而,声明这些类型的变量被称为词法作用域变量。也就是说,它们可以进出存在。如果一个变量在 block 中定义,那么一旦在 block 之外,它将是未定义的。将块视为花括号:
子程序是一个块
sub foo { # Curly brace starts the block
...
} # Curly brace ends the block
这意味着如果你在一个子程序中定义一个变量,它只在那个子程序中。
另外,while 和 for 循环是块:
for my $foo ( @foo_list ) { # The variable $foo is only defined in this loop
...
} # End of block and end of loop
while ( my $foo = <@foo_list> ) { # Again, $foo is only in this block
...
} # End of the block
if ( $foo == $bar ) { # Another block
my $foo = 1; # $foo is defined in the block
} # $foo is no longer defined
你甚至可以只使用花括号:
my $foo = 1;
print "$foo\n" # Prints 1
{
my $foo = 2; # Redefines $foo it's a different $foo!
print "$foo\n" # Prints 2
} # End of block, $foo in block is now out of scope
print "$foo\n"; # Prints 1 because the original $foo is in scope.
让我们看看这个:
my $foo = 2;
my $bar = 5;
print "$foo\n"; # Prints 2
call_sub(5); # Prints "Foo is 5!"
print $foo\n"; # Prints 2
sub call_sub {
my $foo = shift; # Different $foo from main program!
print "Foo is $foo!\n";
print "Bar is $bar\n"; # Will print "Bar is 5" because $bar is in scope
} # Subroutine's $foo falls out of scope
如您所见,$bar 是在我调用子例程之前定义的,因此它是在子例程中定义的,并且仍在范围内。但是,我的子例程中的 $foo 被重新声明,并且一直保留到子例程结束并且超出范围。因此,我的子程序对$foo 的使用不会干扰我的主程序。
所以,回答你的问题:
- 始终使用
use strict;。这将强制您在使用变量之前声明它们。
- 变量只有在使用
my 声明后才会定义。
- 变量的生存和呼吸范围有限。这可能非常有用。不要像在 Pascal 中那样坐在那里用
my 在程序开头声明所有变量。声明它们的使用位置,并在不需要时让它们超出范围。
- 子程序变量不是私有的,因为子程序可以使用已经声明的变量。这是一个坏主意,因为它允许子例程覆盖主程序中变量的值。因此,为了安全起见,请始终使用
my 声明所有子程序变量。
- 当您忘记定义要尝试使用的变量时,请使用
use warnings; 向您发出警告。
最后,我撒了谎,但有一个很好的理由。 Perl 中的变量比我介绍的要复杂一点(很多)。你有命名空间的概念,包变量和本地化变量的方法甚至不是本地的。即使是使用 Perl 多年的人也很难理解其后果。
use strict; 并没有真正强迫你声明变量。它迫使您要么使用用my 声明的词法范围变量,要么对包 变量使用完全限定的变量名(或使用our 声明这些变量)。
但是,最后,use strict; 确实在某种程度上强制您声明一个变量,因为您将在 Perl 中使用的 99% 的变量将使用 my 声明。当您了解更多关于 Perl 的信息时,您可以了解更多关于那 1% 的信息。
如需了解更多信息,请查看PerlSub 关于将my 用于私有变量,并查看PerlMod 以获取关于包变量的完整讨论,使用 local,以及(我怎么会忘记!)新引入的 state 变量。