我已经在Perl中编程了一段时间,但我从未理解过关于Perl的一些细微之处:
$ _变量的使用和设置/取消设置让我感到困惑。例如,为什么
# ...
shift @queue;
($item1, @rest) = split /,/;
工作,但(至少对我而言)
# ...
shift @queue;
/some_pattern.*/ or die();
似乎不起作用?
另外,我不理解使用foreach
与while
迭代文件之间的区别。例如,我似乎得到了不同的结果
while(<SOME_FILE>){
# Do something involving $_
}
和
foreach (<SOME_FILE>){
# Do something involving $_
}
任何人都可以解释这些微妙的差异吗?
答案 0 :(得分:13)
shift @queue;
($item1, @rest) = split /,/;
如果我理解正确,您似乎认为这会将元素从@queue
转移到$_
。事实并非如此。
从@queue
移出的值只会消失以下split
对$_
中包含的任何内容进行操作(独立于shift
调用)。< / p>
while(<SOME_FILE>){
# Do something involving $_
}
从while
语句中的文件句柄中读取是特殊的:它等同于
while ( defined( $_ = readline *SOME_FILE ) ) {
这样,您可以逐行处理甚至是巨大的文件。
另一方面,
for(<SOME_FILE>){
# Do something involving $_
}
首先将整个文件作为行列表加载到内存中。尝试1GB文件,看看差异。
答案 1 :(得分:5)
另一个虽然微妙的区别:
while (<FILE>) {
}
和
foreach (<FILE>) {
}
是while()将修改其范围之外的$ _的值,而foreach()使$ _ local。例如,以下将死:
$_ = "test";
while (<FILE1>) {
print "$_";
}
die if $_ ne "test";
然而,这不会:
$_ = "test";
foreach (<FILE1>) {
print "$_";
}
die if $_ ne "test";
对于更复杂的脚本,这变得更加重要。想象一下:
sub func1() {
while (<$fh2>) { # clobbers $_ set from <$fh1> below
<...>
}
}
while (<$fh1>) {
func1();
<...>
}
就个人而言,由于这个原因,我不会使用$ _,除了它不太可读等等。
答案 2 :(得分:3)
关于第二个问题:
while (<FILE>) {
}
和
foreach (<FILE>) {
}
具有相同的功能行为,包括设置$_
。区别在于while()
在标量上下文中评估<FILE>
,而foreach()
在列表上下文中评估<FILE>
。考虑以下两者之间的区别:
$x = <FILE>;
和
@x = <FILE>;
在第一种情况下,$x
获取FILE
的第一行,而在第二种情况下,@x
获取整个文件。 @x
中的每个条目都是FILE
中的不同行。
因此,如果FILE
非常大,那么使用foreach (<FILE>)
与while (<FILE>)
相比,你会浪费记忆力。这对您来说可能是也可能不是问题。
真正重要的地方是FILE
是否为管道描述符,如:
open FILE, "some_shell_program|";
现在foreach(<FILE>)
必须等待some_shell_program
完成才能进入循环,而while(<FILE>)
可以一次读取some_shell_program
一行的输出并执行与some_shell_program
平行。
尽管如此,关于$_
的行为在两种形式之间保持不变。
答案 3 :(得分:2)
foreach预先评估整个列表。同时评估条件,看看每次传递是否真实。虽然应考虑进行增量操作,但仅适用于列表来源。
例如:
my $t= time() + 10 ;
while ( $t > time() ) { # do something }
答案 4 :(得分:1)
答案 5 :(得分:0)
while
仅检查值是否为真,for
也将值放在$_
中,但在某些情况下除外。例如,<>
如果在$_
循环中使用,则会设置while
。
获得类似的行为:
foreach(qw'a b c'){
# Do something involving $_
}
您必须明确设置$_
。
while( $_ = shift @{[ qw'a b c' ]} ){
# Do something involving $_
}
最好明确设置变量
for my $line(<SOME_FILE>){
}
或更好
while( my $line = <SOME_FILE> ){
}
,一次只读取一行文件。
除非您特别提出$_
,否则shift
不会设置$_ = shift @_;
$_
默认情况下,split
适用于@_
。如果在标量中使用,则void上下文将填充{{1}}。
答案 6 :(得分:0)
这是为了避免这种混淆,以避免使用隐式$ _结构被认为是更好的形式。
my $element = shift @queue;
($item,@rest) = split /,/ , $element;
或
($item,@rest) = split /,/, shift @queue;
同样
while(my $foo = <SOMEFILE>){
do something
}
或
foreach my $thing(<FILEHANDLE>){
do something
}
答案 7 :(得分:0)
请阅读perldoc perlvar
,以便了解Perl中的不同变量。