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初期値から変更したくありません。init$var

エラーはどこにありますか、またはこの問題を解決するためのより良い方法はありますか?

ご挨拶

4

4 に答える 4

3

return $foo if $barと同等$bar and return $fooです。したがって、$barが false の場合、このステートメントは の値に評価されます$bar。サブルーチンは最後に実行されたステートメントの値を返すため、サブルーチンが定義されている場合は値を返し、$var定義されていない場合は偽の値を返します。

明示的なルートに移動して、別のリターンをそこに置くことができます。

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

これは愚かで、 と同等return $varです。

これで、 sub が返す偽の値が実際に定義されたので、に割り当てられ$aます。代わりに、真実をテストできます。

$a = $tmp if $tmp;

…しかし、それはワームの別の缶を開きます.


戻り値は、それらが必要な戻り値なのかエラー インジケーターなのかを伝えるのが非常に苦手です。それを回避する2つのクリーンな方法があります:

  1. 関数が正常に終了したかどうかを示す 2 番目の値を返します。

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

    (基本的には、Golang で見られるコンマ OK イディオム)

  2. 実際の戻り値を取得するために分解する必要があるコンテナーを返します。可能性としてはundef、エラー時に (または何か false を) 返すか、そのような値が存在する場合はその値へのスカラー参照を返すことです:

    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 に答える
3

一時変数を避けることができ、

$a = funct() // $a;
于 2013-08-27T12:38:20.567 に答える
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

于 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 に答える