[旧文搬迁]在不清楚发生了什么前,不要随便使用语法糖


感谢IT牛人博客聚合上还能找到我之前博客的一些内容,因为之前主机没续费等各种原因,也懒得翻之前的备份文档了,就把那上面的文章直接拷过来整理一下好了,只搬迁一些还有意义的内容好了,其他的就让它随风而去吧。

Perl有很多语法糖,可以帮助我们用很少的代码表达更多的意思,其中就包括了Perl的各种内置变量。例如我们今天的主角$_

$_代表循环中的当前元素,我一直以为$_是一个值copy,而且隐约记得小骆驼里说过,当嵌套循环时,内层$_会覆盖外层$_的值,但是当内层循环结束时,$_会恢复成原来的值。一直这么用相安无事,直到今天遇到了bad case,例如:

my @ins = @ARGV;
foreach(@ins) {
    open IN, $_;
    while(my $line = chomp ) {
        print "@ins\n";
    }
    close IN;
}

程序很简单,输入一组文件,然后读取他们的内容。注意到那条打印语句,按我想要的是@ins数组内插,也就是它的元素。但实际上打印出的却是读入的文件的内容。而在内层while循环结束后@ins数组完全被改变了。

百思不得其解,按道理说没有任何语句改变了@ins数组的值,但是它却真的变了。周围找不到人问,于是加了Perl的beginners邮件列表,问了这个问题。

总结起来原因是这样的,是内层的$_改变了外层循环的$_值,也就是改变了@ins数组的值。小骆驼那句话说的有问题?其实没错,只是$_会自动恢复发生在foreach嵌套foreach上,而当内层循环是while时,就不会自动恢复。那我想保留外层数组就只能copy一个?其实不是的,只要不用语法糖,显示的声明lexical variable就可以了。因此只要修改上述代码即可:

my @ins = @ARGV;
foreach my $file (@ins) {
    open $in, ') {
        chomp;
        print "@ins\n";
    }
    close $in;
}

这样就能达到我们想要的效果,在open语句的格式上,maillist上面的朋友说用3个参数的比较好,因此帮我改了。另外,Shawn指出,实际上$_并不是foreach的element的值拷贝,而是真正代表数组的元素,也就是说当内层循环是while时,实际上执行了$_ = current_line的操作,因此会改变数组的值。

今晚收获颇丰,作为一个才写了两个月Perl的人,还是老老实实用显示变量吧,在不清楚Perl内部实际怎么用那些语法糖前,还是少用为妙。糖是甜的,但是吃多了蛀牙还长胖。


文章作者: Odin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Odin !
  目录