2013-08-27 77 views
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的子功能沒有定義從它的初始。

錯誤在哪裏或者有沒有更好的方法來解決這個問題?

問候

回答

3

return $foo if $bar相當於$bar and return $foo。因此,當$bar爲假時,則此語句評估值爲$bar。由於子程序返回最後一次執行的語句的值,所以如果定義了子程序,則返回$var,否則返回假值。

您可以去顯式路由,並把另一個回報有:

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

這是傻了,相當於return $var

現在您的子返回的虛假值實際上已定義,因此它被分配到$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逗號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所見)

    下面是使用無obious臨時辦法乏:

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

Thx!總是很高興閱讀這些詳細的答案。由於我是一名新手,由於我所獲得的洞察力,這是值得接受的答案。我喜歡第一個定義,因爲它在直覺上是可以理解的。 – EverythingRightPlace

+0

我喜歡OP比'($ a)= map {$ _? $$ _:()} func(),\ $ a;'或'($ a)= map {defined $ _? $ _:()} func(),$ a;' –

+0

@mpapec這個'map'表達式不一定意味着被使用。相反,它展示了這可以如何推廣。 (實際上,這是Haskell的勢利小人,突出了'Maybe' monad和Perl的標量之間的相似之處。對於monad,我們需要操作'return:t→t?',它由參考運算符'\'和' bind:t?→(t→u?)→u?',可以表示爲'sub bind {my($ x,$ f)= @_; $ x?$ f - >($$ x):我們也有'mzero'('undef')和'mplus:t?→t?→t?',它是'sub mplus {(grep $ _,@_)[ 0 ...}) – amon

3

你能避免臨時變量,

$a = funct() // $a; 
+0

你能解釋一下嗎? 我改變了你的第二條線,它不工作。 – EverythingRightPlace

+0

也改變'返回$ var如果定義$ var;'''返回$ var;' –

+0

Thx,這個工作。 – EverythingRightPlace

1

在Perl調試運行這個程序表明$tmp爲s並將其寫入空字符串,該函數的結果爲defined。這就是爲什麼設置$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。這將設置$tmpundef

+0

Thx @Zid,從未使用過調試器。將來會嘗試做。 – EverythingRightPlace

0

它看起來像你試圖通過返回undef檢測錯誤情況。除了@阿蒙的建議,您可以diefunct時出現錯誤:

#!/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 [email protected] 
}; 

print "$a\n";