2012-03-08 51 views
4

我試圖調用一個嵌套的遞歸perl函數,但我無法使用正確的語法。嵌套的函數調用作用域和語法

問題:對嵌套函數執行遞歸調用的正確語法是什麼(如果嵌套函數應該被遞歸調用)?

答案:參考接受的答案中的建議僞代碼。

這裏是一個僞代碼片斷:

use Scalar::Util; 
sub outerfunction { 
    my $innerfunction = sub { 
    # Do something 
    innerfunction(); 
    # Do other things 
    }; 
    Scalar::Util::weaken($innerfunction); 
    &$innerfunction(@_); 
}; 

我試圖調用innerfunction如下面的(與相應的錯誤消息):

innerfunction 

未定義子程序&主: :內功能

&innerfunction 

未定義的子程序&主要:: innerfunction

&$innerfunction 

全局符號 「$ innerfunction」 需要明確的包名

我也試着申報innerfunction爲本地,但收到以下內容:

全局符號「$ innerfunction」需要明確的包名

我沒有太多的經驗,解釋型語言,所以涉及到內存/堆泄漏/損壞或與上述僞其他危險(任何意外評論除了遞歸系統限制外)也將不勝感激。

謝謝! 在Linux上2.6.34.7-61.fc13.x86_64

+2

你怎麼使用的參考'weaken'打算? – TLP 2012-03-08 20:12:03

+0

爲什麼使用嵌套函數?你認爲這樣做的好處是什麼? – TLP 2012-03-08 20:14:54

+1

發現了幾個帖子,提示其用法,以防止當函數引用超出範圍時perl解釋程序可能會忽略的過時引用造成的內存泄漏。不過,它似乎並未影響潛在的問題。如果使用weaken()是不可取的,請糾正我的理解。 – WMX 2012-03-08 20:15:41

回答

14

運行的innerfunction()語法的Perl v5.10.1僅適用於已經安裝到符號表(如sub NAME {...}語法確實)子程序。你需要調用你的內部函數$innerfunction->()&$innerfunction(),但是你遇到麻煩的地方在於$innerfunction詞法的範圍。

當您聲明變量爲my時,變量在範圍之後該語句結束。所以,你需要分割你的宣言:

my $innerfunction; 
    $innerfunction = sub { 
     ... 
     $innerfunction->(); 
     ... 
    }; 

爲了打破循環引用與weaken通常的模式是:

use Scalar::Util; 
sub outer_function { 
    my $weak_ref; 
    $weak_ref = my $strong_ref = sub { 
     # Do something 
     $weak_ref->(); 
     # Do other things 
    }; 
    Scalar::Util::weaken($weak_ref); 
    return $strong_ref; 
}; 

所以現在,只要$strong_ref超出範圍,子程序會垃圾收集。

+0

非常感謝 - 這正是我所期待的! – WMX 2012-03-08 20:26:06

+0

你玩過* blead *中新的'__SUB__'功能嗎? – tchrist 2012-03-09 01:46:42

4
sub outer_function { 
    local *inner_function = sub { 
     # Do something 
     inner_function(); 
     # Do other things 
    }; 
    inner_function(); 
}; 

幾乎與下面的那麼好,但仍有許多更加清晰:

use Scalar::Util qw(weaken); 
sub outer_function { 
    my $weak_ref; 
    my $strong_ref = sub { 
     # Do something 
     $weak_ref->(); 
     # Do other things 
    }; 
    weaken($weak_ref = $strong_ref); # Avoid memory leak. 
    $strong_ref->(); 
}; 
+0

要明確的是,頂級版本不會遭受內存泄漏,即使它沒有經歷所有這些扭曲。 'local'提供與'weaken'相同的服務。 (@Eric Strom可能會覺得這很有趣。) – ikegami 2012-03-09 23:43:17

+0

我同意使用'local'更清潔,但實用程序遠遠減少。詞法關閉的優勢在於它可以被返回(正如我的答案所示)。如果你試圖從你的第一個例子中返回coderef然後調用它,最好你會得到一個關於調用一個未定義子例程的致命錯誤,並且最壞的情況是你會調用一個不相關的但是像命名的子例程,導致各種意想不到的行爲。我在我的回答中做出了假設,即OP僅顯示一個簡短的例子,並希望在外部範圍中使用coderef。如果不是,那麼我同意「本地」運作良好。 – 2012-03-10 21:05:24

+0

重新「但效用大大降低」,我已經完成了「數以百萬計的」遞歸函數,並且沒有任何弱化,所以它並沒有減少太多。 「如我的答案所示」,是的,我注意到你偏離了這個問題。大多數遞歸函數都可以受益於非遞歸包裝,在這種情況下,遞歸部分本身應該是私有的。這不是創建閉包的問題。 – ikegami 2012-03-11 09:32:17