【问题标题】:How do I return nothing from a subroutine?如何从子例程中不返回任何内容?
【发布时间】:2009-10-22 22:14:28
【问题描述】:

我想在执行下一步之前验证一个条件,但只发出警告并跳过当前值而不是死掉。

如何重写 validate_me() 子程序而不返回任何值?

(更新) 请注意,以下代码按预期工作,只是我想要其他东西,而不是从 validate_me() 返回 1 或 0,这仍然允许代码表现相同。

foreach my $file ( @files ) {
    validate_me($foo, $bar, $baz) or next;
    do_something();
}  

sub validate_me {
    my ($foo, $bar) = @_;

    if ( $foo > $bar ) {
        carp("Something goes awol");
        return 0;
    }

    if ( $bar != $baz ) {
        carp("Odd");
        return 0;
    }

    return 1; # success
}

谢谢。

【问题讨论】:

  • 您为什么不想以标准方式表明您的验证程序是否成功?您可能会返回 undef 为 false,或者绝对是一个空字符串;您可以返回 2 或 100 或 -1 或类似 0E0 之类的奇怪值,它为零但不为真。但是为什么不以理智的方式去做——就像你当前的代码一样?
  • 我被 Paul Fenwick 的主题“克林贡编程的艺术”感染了,通常情况下,最好从子例程中终止/警告,而不是返回要检查的值。也许在我的上下文中这不是合适的技术。
  • 你的子程序是警告,当它返回 0 时。你说你不想让它死(它不会)你不想要一个返回值,但是删除返回语句会破坏代码 => 你想要什么

标签: perl


【解决方案1】:

查看return 的文档。如果您不想返回任何内容,请不要给 return 一个参数:

 return;

【讨论】:

  • 我知道,但是如何在没有 validate_me() 返回 1 或 0 的情况下重写上面的代码 sn-p?
  • 好吧,在你有回报的地方,使用我刚刚给你的那行代码。
  • @brian:一味地把所有的行都换成“return”,包括最后的“return 1”当然会导致代码中断?
  • 如果你想更详细,你可以显式写return();说:“真的只是什么都不返回”。
  • @est:我不知道你在害怕什么。在代码中您不想返回任何内容的地方,您就有了答案。我认为你对自己太苛刻了。
【解决方案2】:

首先,没有理由在循环中使用标签,next; 本身会自动执行封闭循环的下一次迭代。

至于你的问题,我对你想要完成的事情有点困惑。如果您的任何测试失败,您编写的代码将从validate_me 返回零,这是一个错误值,这将导致循环的下一次迭代。 validate_me 中没有任何东西会导致任何东西死亡。

【讨论】:

  • 我不想让它死掉,只是发出警告。
  • Damian 在 PBP 中提出的一个更好的想法是用 next/last/repeat 标记您要跳入的任何循环。我认为这是个好主意,而且您还可以免费获得循环和每个退出点的文档。
  • @est,您发布的代码中没有任何内容会导致任何东西死亡。 carp 发出警告。没有其他东西可以导致致命错误。尝试更新您的问题,以更具体地说明您要完成的工作。
  • 有很多理由来标记循环。我什至在非嵌套循环中也这样做,以表明我正在迭代的内容。
【解决方案3】:

更新:

我想要其他东西,而不是从 validate_me() 返回 1 或 0,它们仍然允许代码表现相同。

这是你的意思吗?见eval

my @files = qw( a b c d e f );

FILES:
foreach my $file ( @files ) {
    eval { validate_me($file) };
    if (my $ex = $@) {
        warn "'$file' failed validation: $ex";
        next FILES;
    }
    print "$file passed\n";
}

sub validate_me {
    my ($file) = @_;
    die "Invalid filename\n" if 0.5 > rand;
    return; # explicitly return nothing
}

现在,明智的做法是将validate_me 重构为其组件:

for my $file ( @files ) {
    if ( is_something_gone_awol($file, $mile) ) {
        warn "Something has gone awol: '$file' and '$mile'\n";
    }
    elsif ( is_something_odd($file, $smile) ) {
        warn "Something is odd: '$file' and '$smile'\n";
    }
    else {
        do_something($file);
    }
}

sub is_something_gone_awol {
    my ($foo, $bar) = 0;
    return $foo gt $bar;
}

sub is_something_odd {
    my ($bar, $baz) = @_;
    return $bar ne $baz;
}

【讨论】:

  • 我是 :) 可能是我没有清楚地表达我的问题。您的解决方案仍然从 validate_me() 返回 1,而我想要实现的是让代码的行为与我的示例相同,但不检查 validate_me() 的返回值。
  • 顺便说一句,这里返回 undef 而没有 die/eval 是一样的。
【解决方案4】:

return; 将结束函数,不问任何问题。

但如果您想知道,您还可以使用作为参数传递给函数的指针/引用来返回值。

void foo(int input, outStruct *output) {
...
output = new outStruct(...); //for example;
return;
};

编辑 我是个白痴,看不懂标签/代码。该示例使用 C/C++,而不是 Perl。 哎呀。

【讨论】:

  • 你错过了 [perl] 标签吗?
  • 他的观点仍然有效,即使示例使用了错误的语言——函数可以更新作为参数传入的引用的内容,并以这种方式将值传递回调用者.
【解决方案5】:

您可以return undef只是return

【讨论】:

  • 永不返回 undef。这为您提供了一个项目列表,这几乎不是您想要的。
  • 如果您执行@a = validate_me()(或者,在 CGI::param 的常见错误来源中,类似于 %a = ( 'valid' => validate_me(), ... )
  • 考虑“my $foo = do { return undef }; say 'false' unless $foo ==> false;”和“my @foo = do { return undef }; say 'true' if @foo ==> 'true'”。这是一个令人困惑的 API。我会同意布赖恩的观点,并说永远不要“返回 undef”。
  • 我也必须在这里第二次 brian 永远不会返回 undef。过去,当我的子程序在列表上下文中返回 undef 时,我曾多次被它打败。
  • 在标量上下文中,return undefreturn 之间没有区别。在列表上下文中,return undef 将返回一个真值。因此,从不明确返回 undef 没有任何缺点。
猜你喜欢
  • 1970-01-01
  • 2016-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
相关资源
最近更新 更多