0

我怎样才能避免变量被子函数的返回所触及。我写了以下代码片段

#!/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改变它的初始值initif$var没有在子函数中定义,

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

问候

4

4 回答 4

3

您可以避免临时变量,

$a = funct() // $a;
于 2013-08-27T12:38:20.567 回答
3

return $foo if $bar相当于$bar and return $foo。_ 因此,当$bar为假时,此语句的计算结果为$bar。当子例程返回最后执行的语句的值时,$var如果它已定义,则您的子程序返回,如果未定义,则返回 false 值。

您可以走显式路线,然后在此处放置另一个返回:

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

这很愚蠢,相当于return $var.

现在您的 sub 返回的 false 值实际上已定义,因此它被分配给$a. 您可以改为测试真相:

$a = $tmp if $tmp;

......但这会打开另一罐蠕虫。


返回值在告诉我们它们是想要的返回值还是错误指示方面非常糟糕。有两种干净的方法:

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

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

    (基本上,在 Golang 中看到的 comma-ok 成语)

  2. 返回一个必须被解构以获得实际返回值的容器。一种可能性是在错误时返回undef(或某些错误),或者在存在此类值时对该值进行标量引用:

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

    (基本上是Maybe在 Haskell 中看到的一种类型)

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

    ($a) = map { $_ ? $$_ : () } func(), \$a;
    
于 2013-08-27T12:44:14.450 回答
1

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

$ 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. 这将设置$tmpundef

于 2013-08-27T12:44:17.560 回答
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";
于 2013-08-27T14:06:44.420 回答