【问题标题】:Nested function calls in PerlPerl 中的嵌套函数调用
【发布时间】:2016-02-24 19:53:00
【问题描述】:

我不得不为我的工作编辑一些 Perl 脚本。我从来没有写过一行 Perl,但我可以让我的东西正常工作,直到我遇到了一个奇怪的问题。考虑以下函数

sub trim {
    my $s = shift; 
    $s =~ s/^\s+|\s+$//g; 
    return $s 
}

有以下两种调用方式:

my $previousVersionHash = readline( *CONFIG );
$previousVersionHash = trim($previousVersionHash);
$maxClients = readline( *CONFIG );

my $previousVersionHash = trim(readline( *CONFIG ));
$maxClients = readline( *CONFIG );

在第一种情况下,它工作正常,但使用第二个 sn-p 我收到警告,$maxClients 是空的,而不是包含 CONFIG 文件的第二行。

为什么会有这种奇怪的行为?请注意,这也发生在我使用sub trim($) 时。顺便说一句,我不知道这两个声明之间的区别,但这是记录在案的,所以我可以看看它是否对这个问题很重要。

【问题讨论】:

  • 如果你说sub trim($),问题应该不会发生。也就是说,学习处理为其 args 提供列表上下文的子调用会比弄乱原型更好,因此首选 trim(scalar readline...)
  • 如果测试这个对我来说不是那么痛苦,我会尝试添加回参数列表

标签: perl


【解决方案1】:

如果 Perl 想要返回一个列表或一个标量,它会让它现在调用的函数。您可以使用wantarray 进行检查。 readline 当您在列表上下文中调用它时,会将所有行读入一个数组,就像您在第二个示例中所做的那样。

第二种方式是这样调用它,因为(就像@ThisSuitIsBlackNot 的评论所说)用户定义的子例程的参数总是在列表上下文中评估(假设没有原型):

my @array = readline( *CONFIG );
trim(@array);

所以这里*CONFIG 的所有其余行都放入数组@array。您的 trim 函数会丢弃除第一个以外的所有其他值。

要解决这个问题并强制对 trim 的调用处于标量上下文中,请执行以下操作:

my $previousVersionHash = trim(scalar(readline( *CONFIG )));

或者像你一样继续调用它。

要更新 trim 以支持数组,您可以尝试以下操作:

sub trim {
    my @a;
    foreach my $s (@_) {
        $s =~ s/^\s+|\s+$//g; 
        push @a, $s;
    }
    return @a;
}

【讨论】:

  • 好的,这很酷,所以我可以根据需要将修剪功能应用于所有行,然后简单地从数组中读取。这将使我的其余代码稍微好一点:) 干杯!
  • 上下文是 Perl 中一个令人困惑但功能强大的功能,而不是您在任何其他语言中可能遇到的功能。
  • 除非它将一个数组传递给trim?我去看看
  • s/array context/list context/。另外,我认为您在这里遗漏了关键点:用户定义的子例程的参数始终在列表上下文中进行评估(假设没有原型)。
  • @ThisSuitIsBlackNot:谢谢。更新了我的答案。我确实告诉过 sub 是在列表上下文中评估的,即使我没有把它拼出来。