未定义的子回报

时间:2013-08-27 12:29:24

标签: perl function return return-value

如何通过返回子功能来避免变量被触及。我写了以下代码片段

#!/usr/bin/perl
use strict;
use warnings;

my $a = "init";

sub funct{
    my $var;
    #$var = 1;
    return $var if defined $var;
}

my $tmp = funct;

$a = $tmp if defined $tmp;
print "$a\n";

如果子函数中未定义$a,我不希望init的值从其初始$var更改。

错误在哪里或有更好的方法来解决这个问题?

问候

4 个答案:

答案 0 :(得分:3)

您可以避免临时变量,

$a = funct() // $a;

答案 1 :(得分:3)

return $foo if $bar相当于$bar and return $foo。因此,当$bar为false时,此语句将计算为$bar的值。当子例程返回最后执行的语句的值时,如果定义了子语句,则子语句返回$var,如果没有,则返回false值。

您可以选择显式路线,然后再返回:

# all branches covered
return $var if defined $var;
return;

这很愚蠢,相当于return $var

现在您的子返回的假值实际上已定义,因此它被分配给$a。你可以测试一下真相:

$a = $tmp if $tmp;

......但这会打开另一种蠕虫病毒。


返回值非常不好告诉我们它们是否是所需的返回值或错误指示符。有两种方法:

  1. 返回第二个值,告诉我们函数是否退出OK:

    sub func {
      my $var;
      return (1, $var) if defined $var;
      return (0);  # not strictly needed
    }
    
    my ($ok, $tmp) = func();
    $a = $tmp if $ok;
    

    (基本上,在Golang中看到的逗号成语)

  2. 返回必须解构的容器以获取实际返回值。可能是在出现错误时返回undef(或错误),或者在存在这样的值时对值进行标量引用:

    sub func {
      my $var;
      return \$var if defined $var;
      return undef;  # actually not needed
    }
    
    my $tmp = func();
    $a = $$tmp if defined $tmp;
    

    (基本上,在Haskell中看到的Maybe类型)

    这是一种在没有冷静的临时变量的情况下使用它的方法:

    ($a) = map { $_ ? $$_ : () } func(), \$a;
    

答案 2 :(得分:1)

在Perl调试器中运行此程序显示$tmp设置为空字符串,使用defined函数计算结果为true。这就是设置$a的条件求值为true的原因:

$ perl -d

Loading DB routines from perl5db.pl version 1.33
Editor support available.

Enter h or `h h' for help, or `perldoc perldebug' for more help.

use strict;
use warnings;

my $a = "init";

sub funct{
    my $var;
    #$var = 1;
    return $var if defined $var;
}

my $tmp = funct;

$a = $tmp if defined $tmp;
print "$a\n";
__END__
main::(-:4):    my $a = "init";

  DB<1> x $a
0  undef

  DB<2> n
main::(-:12):   my $tmp = funct;

  DB<2> x $a
0  'init'

  DB<3> x $tmp
0  undef

  DB<4> n
main::(-:14):   $a = $tmp if defined $tmp;

  DB<4> x $tmp
0  ''

仅使用return $var修复if defined $var。这会将$tmp设置为undef

答案 3 :(得分:0)

看起来您正在尝试通过返回undef来检测错误情况。除了@ amon的建议,当发生错误时,die可以funct

#!/usr/bin/perl
use strict;
use warnings;

my $a = "init";

sub funct{
    my $var;
    ...
    if ($something_went_wrong) {
       die 'something bad';
    }
    ...
    return $var;
}

eval {
    $a = funct;
    1;
} or do {
    # log/handle the error in $@
};

print "$a\n";