【问题标题】:What does Perl return from a subroutine when no return statement is encountered?当没有遇到 return 语句时,Perl 从子例程返回什么?
【发布时间】:2017-12-22 13:45:23
【问题描述】:

我今天遇到了这个问题,并认为发布问答是谨慎的,因为我找不到类似的东西。
如果您发现此问题的重复,请随时投票结束。


以下子程序有条件地returns 输出;我认为它“笨拙”,因为它没有明确说明当条件不满足时返回给调用者的内容:

sub is_multiple_of_three {

    my ( $value ) = @_ ;
    return "$value is a multiple of 3"
      unless $value % 3;
}

快速重写使澄清(更优雅的)子例程在所有情况下的预期行为变得很短:

sub is_multiple_of_three { 

    my ( $value ) = @_ ;
    return if $value % 3;
    return "$value is a multiple of 3";
}

当调用这两种风格的子例程时,我期望在列表上下文中找到return 之间的一些一致性:

  • 条件计算结果为真时的字符串
  • 当条件计算结果为假时,什么都没有(空列表)

但是很可惜,这种行为有点出乎意料:

use strict;
use warnings;
use Data::Printer;
use feature 'say';

my %subs = (
            graceful => sub {
                            my ( $value ) = @_ ;
                            return if $value % 3;
                            return "$value is a multiple of 3";
                        },

              clumsy => sub {
                            my ( $value ) = @_ ;
                            return "$value is a multiple of 3"
                              unless $value % 3;
                        },
           );

for my $name ( keys %subs ) {

    my $sub = $subs{$name};
    say $name;
    my @results = map { $sub->($_) } 1 .. 10;
    p @results;
}

输出

graceful
[
    [0] "3 is a multiple of 3",
    [1] "6 is a multiple of 3",
    [2] "9 is a multiple of 3"
]
clumsy
[
    [0] 1,
    [1] 2,
    [2] "3 is a multiple of 3",
    [3] 1,
    [4] 2,
    [5] "6 is a multiple of 3",
    [6] 1,
    [7] 2,
    [8] "9 is a multiple of 3",
    [9] 1
]

问题

“优雅”的风格表现如预期,但为什么“笨拙”的子在条件为假时返回整数?

【问题讨论】:

标签: perl


【解决方案1】:

该行为与perldoc perlsub 中记录的内容一致

return 语句可用于退出子程序,可选 指定返回值,该值将在 取决于上下文的适当上下文(列表、标量或无效) 的子程序调用。 如果不指定返回值,子程序 在列表上下文中返回一个空列表,标量中的未定义值 上下文,或者在无效上下文中什么都没有。如果您退回一个或多个 聚合(数组和散列),这些将被展平成 一大份难以区分的清单。

如果没有找到返回值,并且如果最后一个语句是表达式,则返回它的值。如果最后一条语句是循环控制结构,如 foreachwhile ,则返回值未指定。空子返回空列表。


列表上下文中的优雅子

  • True:返回字符串"$value is a multiple of 3"被返回

  • False : 返回一个空列表

这就是@results中只有三个元素的原因;只有当条件计算为真时,才会将某些内容添加到数组中。

列表上下文中的笨拙子

  • True : 返回字符串 "$value is a multiple of 3" 被返回。这里没有戏剧。
  • False : 因为没有遇到显式的return,所以返回最后一个表达式的值,$value % 3

所以在这两种情况下,子例程都会返回一个值,这就是@results 中有十个项目的原因。

【讨论】:

  • 这对我来说是个难题——“笨拙”中的最后一个“东西”是if (not ...)。文档为“表达式”或“循环控制结构”指定了行为……那么ifnot 呢?看来他们“不算数”,它仍然返回最后的评估。然而,这也可能发生在“未指定”的情况下——我们在这里得到了值,但在其他一些情况下,它可能是别的东西。
  • perlsyn 中查看Statement Modifiers EXPR 示例
  • 我问的是在计算表达式之后 会发生什么 - 执行的是 unless(应该是 not 后跟 if)。文档似乎没有具体说明当最后一件事是 if 时会发生什么。
  • @zdim 让我在这里重新发表评论:有趣的是,将笨拙的 sub 更改为 return if not $value % 3 会导致返回空字符串,而不是模数的结果
  • 哇,现在这是一个发现(对我来说)。所以unless 的行为与if not 不同,在某种程度上会产生后果。我不是指句法差异(例如,不能做EXPR for my $var LIST),而是处理顺序。从您的示例看来,在unless EXPR 中完成的最后一件事实际上是对EXPR 的评估,而在if (! EXPR) 中似乎是if
【解决方案2】:

对于最后一个表达式,foo if barif (bar) { foo } 等价于 bar and foo,同样,除非等价于 or。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 2022-12-09
    • 2011-04-13
    • 2021-09-10
    • 2018-11-20
    • 2019-09-17
    • 2016-06-12
    相关资源
    最近更新 更多