2.local有何好处?
因为local实际不创建本地变量,它并非很有用。在上述示例里,假如B碰巧修改了$lo的值,这样A设置的值就被覆盖掉。这点我们确实不想它发生。我们希望每个函数有它自己的变量,它们不会被其他函数触及到。这就是my所能做到的。
为 什么会有local呢?答案90%是因为历史原因。早期的perl版本仅有全局变量。local非常容易执行,它作为对本地变量问题的局部解决方案而增加 到perl4里。后来在perl5里做了更多工作,真正的本地变量被添加到该语言里。不同于local,新的本地变量以单词my来申明。之所以选择 my,是因为它暗示着隐私,也因为它非常短;短小的单词也许会鼓励你使用它来代替local。my也比local运行更快。
何时使用my,以及何时使用local呢?
答案很简单:总使用my,绝不要使用local。
3.my变量的其他特性
每次控制抵达my申明,perl创建一个新的,初始的变量。例如,如下代码打印x=1 50次:
每次遍历循环时,你得到一个新的$x,其值初始化为undef。
假如申明在循环之外,控制只会通过它一次,所以这里就只有一个变量:
这会打印x=1, x=2, x=3, ... x=50.
可 以利用这点来玩个游戏。假设有个函数,它需要从一个调用到下一个调用中记住某个值。例如,考虑一个随机数产生器。典型的随机数产生器(类似perl的 rand函数)有个种子在其中。种子就是一个数。当请求随机数产生器来获取随机数时,该函数基于种子来执行某些运算,然后返回结果。它也会存储该结果,并 将其作为下一次函数调用的种子。
如下是典型代码:
典型的输出:
16838
14666
10953
11665
7451
26316
27974
27550
这里有个问题,因为$seed是个全局变量,那意味着我们必须担忧某个人可能无意中修改它。或者别人有意破坏它,这就影响了程序的结果。假如该函数用于赌博程序中,并且别人破坏了它的随机数产生器,你想想会发生什么?
但是我们不能在函数里申明$seed为my变量:
假如这样做了,当每次调用my_rand时,$seed会被初始化为undef。我们实际需要的是,在每次调用my_rand时,$seed会保留其值。
如下是解决方法:
申明在函数之外,所以它仅仅在程序编译时执行一次,而不是每次函数调用时都执行。但它是个my变量,并且其位于代码块里,所以它仅对块里的代码可见。my_rand是块里的唯一其他东西,所以$seed仅可被my_rand函数访问。
4.关于my变量的补充
1)不能对以标点符号命名的变量使用my申明,例如_, @_, 或$$。也不能对后台引用的变量$1, $2, ... 使用my申明。my的作者认为那会把事情搞糟。
2)明显的,不能申明my $DBI::errstr,因为那会有冲突:它认为包变量$DBI::errstr是个词法变量。但是可以申明local $DBI::errstr;它存储local $DBI::errstr的当前值,并在代码块结束处恢复它。
3)在perl 5.004及更高版本里,可以这样写:
foreach my $i (@list) {
它限制$i在循环范围内。类似的,
for (my $i=0; $i<100; $i++) {
限制了$i在for循环里。
(三)变量申明
假如你在编写某个函数,并且你想要它有私有变量,就必须使用my来申明变量。假如忘记了,会发生什么事?
sub function {
$x = 42; # Oops, should have been my $x = 42.
}
在该情形下,你的函数修改了全局包变量$x。假如你在其他地方要用到那个包变量,那对程序将是灾难。
最近版本的perl有针对这点的保护选项,你可以激活它。假如放置:
use strict 'vars';
在程序的顶部,perl将要求包变量有明确的包限定词。$x=42里的$x没有这样的限定词,所以程序甚至不会通过编译;代替的,编译器会异常中断,并输出如下错误消息:
Global symbol "$x" requires explicit package name at ...
假如你希望$x是个私有my变量,你可以回头增加my。假如你确实想使用全局包变量,你能回头改变它为:
$main::x = 42;
或其他相应的包。
use strict还有其他的检测选项,请看perldoc strict的更多细节。
现在假设你在编写Algorithms::KnuthBendix模块,你想使用strict vars保护模式,但假如任何时候你需要一遍又一遍的敲入$Algorithms::KnuthBendix::Error,你会觉得很烦。
你可以告诉strict vars生成一个例外:
这样就在你使用短名字$Error时,避免了包变量$Algorithms::KnuthBendix::Error导致的strict vars失败。
如下写法,也可以在某个代码块里关闭strict vars:
(四)总结
包变量总是全局的。它们有一个名字和一个包限定词。可以忽略包限定词,这样perl会使用默认的包,默认包可由package申明设定。对私有变量,请使用my。不要使用local,它已过时。
避免使用全局变量,因为它难以确保程序的2部分不会错误的使用对方的变量。
为了避免意外使用全局变量,请在程序里使用use strict 'vars'。它会检查并确保所有的变量要么是申明为私有的,要么明确使用了包限定词,要么明确使用use vars来申明。
(五)关于'our'的补充
perl 5.6.0介绍了一个新的our(...)申明。它的语法与my()相同,它是use vars的代替品。
如果不深究细节,our()就类似于use vars;它的唯一影响是申明变量,以便它们免除strict 'vars'的检查。然而相对于use vars,它可能有2个优势:语法不那么怪异,影响是词法作用域。也就是说,它让stict检查失效的范围仅仅在当前块之内:
所以使用use vars '$x'申明时,可以在任何地方使用全局变量$x。our($x)仅仅允许在程序的某些块里申明全局变量$x,假如意外的在其他地方使用它,仍会导致错误。