一些Perl的细微之处

时间:2009-08-25 19:30:16

标签: perl

我已经在Perl中编程了一段时间,但我从未理解过关于Perl的一些细微之处:

$ _变量的使用和设置/取消设置让我感到困惑。例如,为什么

# ...
shift @queue;
($item1, @rest) = split /,/;

工作,但(至少对我而言)

# ...
shift @queue;
/some_pattern.*/ or die();

似乎不起作用?

另外,我不理解使用foreachwhile迭代文件之间的区别。例如,我似乎得到了不同的结果

while(<SOME_FILE>){  
    # Do something involving $_        
}

foreach (<SOME_FILE>){
    # Do something involving $_
}

任何人都可以解释这些微妙的差异吗?

8 个答案:

答案 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中的不同变量。

perldoc perlvar