没有遇到return语句时,Perl从子例程返回什么?

Zai*_*aid 3 perl

我今天遇到了这个问题,并认为发布问答集是明智的选择,因为我找不到类似的内容。
如果发现此问题重复,请随时投票关闭。


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

sub is_multiple_of_three {

    my ( $value ) = @_ ;
    return "$value is a multiple of 3"
      unless $value % 3;
}
Run Code Online (Sandbox Code Playgroud)

快速重写使在所有情况下阐明(更优美的)子例程的预期行为的简短工作:

sub is_multiple_of_three { 

    my ( $value ) = @_ ;
    return if $value % 3;
    return "$value is a multiple of 3";
}
Run Code Online (Sandbox Code Playgroud)

当调用这两种子例程时,我期望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;
}
Run Code Online (Sandbox Code Playgroud)

输出量

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
]
Run Code Online (Sandbox Code Playgroud)

“优美的”风格的行为符合预期,但是当条件为false时,为什么“笨拙的”子函数返回整数?

Zai*_*aid 5

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

A return statement may be used to exit a subroutine, optionally specifying the returned value, which will be evaluated in the appropriate context (list, scalar, or void) depending on the context of the subroutine call. If you specify no return value, the subroutine returns an empty list in list context, the undefined value in scalar context, or nothing in void context. If you return one or more aggregates (arrays and hashes), these will be flattened together into one large indistinguishable list.

If no return is found and if the last statement is an expression, its value is returned. If the last statement is a loop control structure like a foreach or a while , the returned value is unspecified. The empty sub returns the empty list.


The graceful sub in list context:

  • True : returns the string "$value is a multiple of 3" is returned

  • False : returns an empty list

Which is why there are only three elements in @results; something is added to the array only when the conditional evaluates to true.

The clumsy sub in list context:

  • True : returns the string "$value is a multiple of 3" is returned. No dramas here.
  • False : as no explicit return is encountered, returns the value of the last expression evaluated , $value % 3

So in both cases, the subroutine will return back a value, which is why @results has ten items in it.