Perl默认变量$ _

时间:2010-08-21 21:35:28

标签: perl

我以为我了解地图然而以下结果我不明白。我知道为什么会这样,我只是不知道它是怎么回事。

问题是@array的内容正在发生变化,因为在$_调用期间_do_stuff_to_file正在重置。所以当我希望它是here: \nhere:\n时,打印的是here: donkie\nhere: kong\n

注意:这不是经过测试的代码。这就是我记得从实验室看到的东西。为什么@array的内容会发生变化?

如果我在$_返回1之前将$f设置为_some_func。然后阵列仍然完好无损。

这是一个示例程序,用于说明我所看到的内容:

my @array = ("donkie", "kong");
map { push @junk, _some_func('blah', $_); } @array;

if (join ('', @junk) !~ /0/)
{   # for example sake this is always true since return 1 from _some_func.
    print map { "here: $_\n"; } @array;
}

sub _some_func
{   # for example sake, lets say $f always exists as a file.
    my $j = shift;
    my $f = shift;
    return 0 if !open(FILE, "< $f");
    close FILE;
    _do_stuff_to_file($f);

    return 1;
}


sub _do_stuff_to_file
{
    my $f = shift;
    open(IN, "< $f");
    open(OUT, "> $f.new");

    while (<IN>)
    {
        print OUT;
    }

    close IN;
    close OUT;
}

4 个答案:

答案 0 :(得分:9)

Perl中的许多函数都使用默认变量$_。其中包括map和readline运算符<>。与foreach类似,map使循环变量成为它处理的列表的每个元素的别名。发生了什么事情就是这一行:

while (<IN>)
$_的别名生效时,

正在分配给map。这是使用$_(或任何其他全局变量)的问题之一 - 远距离的奇怪动作。如果您要使用$_,请先将其本地化:

local $_;
while (<IN>)
...

或者,改为使用词法变量:

while (my $line = <IN>)

答案 1 :(得分:4)

修改$ _将改变你的初始数组,因为$ _是当前元素的别名。您的代码应如下所示:

my @array = ("donkie", "kong");
my @junk=map {_some_func('blah', $_) } @array;

if (join ('', @junk) !~ /0/)
{   # for example sake this is always true since return 1 from _some_func.
    print map { "here: $_\n"; } @array;
}

sub _some_func
{   # for example sake, lets say $f always exists as a file.
    my $j = shift;
    my $f = shift;
    return 0 if !-e $f;
    _do_stuff_to_file($f);
    return 1;
}


sub _do_stuff_to_file
{
    my $f = shift;
    local $_;
    open(IN, "<",$f);
    open(OUT, ">", "$f.new");

    while (<IN>)
    {
        print OUT;
    }

    close IN;
    close OUT;
}

P.S。 map返回具有相同元素数的数组(如果从块返回标量)。 grep只返回块为true的元素。

答案 2 :(得分:4)

大多数设置$ _的东西都隐含了别名,所以不会导致这个问题;例外是while (<filehandle>)。虽然你可以本地化$ _(理想情况下是my $_;),但最好永远不要让隐式设置$ _。请改为while ( my $line = <filehandle> )。 (特殊的隐式定义的()仍然会发生。)

答案 3 :(得分:0)

我赞同亚历山大和迈克尔的答案:_do_stuff_to_file()正在改变$_的价值。 正如map $_的上下文只是存储映射元素的名称一样,数组也会更改。

Alexander和Michael建议更改_do_stuff_to_file(),以免影响$_值。这是本地化特殊变量(例如$_)以避免扰乱外部范围的好习惯。

这是一个避免触及该功能的替代解决方案:在调用函数之前通过本地化来“中断”地图块内的链接:

map { my $x=$_; local $_; push @junk, _some_func('blah', $x); } @array;

或更多遵循共同风格:

@junk = map { my $x=$_; local $_; _some_func('blah', $x) } @array;