2009-02-06 110 views
2

我從來沒有使用嵌套函數,但已經看到幾種語言(以及嵌套類,我認爲是相關的)對它們的引用。什麼是嵌套函數?他們是爲了什麼?

  • 什麼是嵌套函數?
  • 爲什麼?!?
  • 你可以用嵌套函數做什麼,你不能做任何其他的方式?
  • 你可以用嵌套函數做什麼,這是困難或不雅觀,沒有嵌套函數?

我認爲嵌套函數只是將所有對象視爲對象的工件,並且如果對象可以包含其他對象,那麼它就會遵循。

嵌套函數是否具有作用域(通常,我認爲語言不同),就像函數內的變量有作用域一樣?

如果您不確定您的答案是否與語言無關,請添加您所參考的語言。

- 亞當

回答

4

嵌套函數的一個流行用法是closures。在具有一流功能的lexically scoped語言中,可以使用函數來存儲數據。在計劃一個簡單的例子是一個計數器:

(define (make-counter) 
    (let ((count 0))    ; used to store the count 
    (define (counter)    ; this is the counter we're creating 
     (set! count (+ count 1)) ; increment the count 
     count)      ; return the new count 
    counter))      ; return the new counter function 

(define mycounter (make-counter)) ; create a counter called mycounter 

(mycounter)      ; returns 1 

(mycounter)      ; returns 2 

在這個例子中,我們嵌套函數化妝櫃檯裏面的函數計數器,並通過返回這個內部函數中,我們都能夠訪問可用的數據來對抗時,被定義。該信息對mycounter的這個實例是私有的 - 如果我們要創建另一個計數器,它將使用不同的地點來存儲內部計數。從繼續前面的例子:

(define mycounter2 (make-counter)) 

(mycounter2)      ; returns 1 

(mycounter)      ; returns 3 
1

(C#): 我用它來簡化對象瀏覽器視圖,並更好地構建我的班。 由於班輪嵌套在卡車類。

不要忘了這個細節: 「嵌套類型可以訪問包含類型的私有和受保護成員,包括任何繼承的私有或受保護成員。」

2

當是永遠不會把它叫做

string[] GetFiles(string path) 
{ 
    void NestedGetFiles(string path, List<string> result) 
    { 
    result.AddRange(files in the current path); 
    foreach(string subPath in FoldersInTheCurrentPath) 
     NestedGetFiles(subPath, result); 
    } 

    List<string> result = new List<string>(); 
    NestedGetFiles(path, result); 
    return result.ToArray(); 
} 

只有1種方法上面的代碼是完全由而是基於C#給予這對遞歸有用我的意思是想法。唯一可以調用NestedGetFiles的方法是GetFiles方法。

1

嵌套函數允許您封裝僅與該函數內的一個函數的內部工作相關的代碼,同時仍允許您將該代碼分離以實現可讀性或泛化。在一些實現中,它們也允許訪問外部範圍。在D:

int doStuff() { 
    int result; 
    void cleanUpReturn() { 
     myResource1.release(); 
     myResource2.release(); 
     return result * 2 + 1; 
    } 

    auto myResource1 = getSomeResource(); 
    auto myResource2 = getSomeOtherResource(); 
    if(someCondition) { 
     return cleanUpReturn(); 
    } else { 
     doSomeOtherStuff(); 
     return cleanUpReturn(); 
    } 
} 

當然,在這種情況下,這也可以用RAII來處理,但這只是一個簡單的例子。

2

嵌套函數只是另一個函數內的函數。

是的,它是一切物體的結果。由於變量只能在函數的作用域中可見,並且變量可以指向函數,因此可以使用由局部變量引用的函數。

我不認爲有什麼你可以做一個嵌套函數,你絕對不能沒有。不過,很多時候它是有意義的。也就是說,每當函數是某個其他函數的「子函數」時。

對我來說,一個常見的用例是函數執行很多複雜的邏輯,但函數計算/返回的內容很容易針對邏輯所規定的所有情況進行抽象。

1

如果您需要將函數作爲參數傳遞給另一個函數,它們也可能很有用。它們也可以是用於製造工廠函數工廠函數(在Python)有用:

>>> def GetIntMaker(x): 
... def GetInt(): 
...  return x 
... return GetInt 
... 
>>> GetInt = GetIntMaker(1) 
>>> GetInt() 
1 
1

嵌套函數只是另一個函數的主體內限定的功能。爲什麼?關於我能想到的唯一理由就是助手或實用功能。

這是一個人爲的例子,但忍受着我。假設您有一個函數必須針對結果執行兩個查詢,並使用其中一個查詢的值填充對象。你可以做如下的事情。

function process(qryResult q1, qryResult q2) { 

    object o; 
    if (q1.someprop == "useme") { 
     o.prop1 = q1.prop1; 
     o.prop2 = q1.prop2; 
     o.prop3 = q1.prop3; 
    } else if (q2.someprop == "useme") { 
     o.prop1 = q2.prop1; 
     o.prop2 = q2.prop2; 
     o.prop3 = q2.prop3; 
    } 

    return o; 

} 

如果您有20個屬性,您將複製代碼以反覆設置對象,從而導致巨大的功能。您可以添加一個簡單的嵌套函數來執行從查詢到對象的屬性副本。像這樣:

function process(qryResult q1, qryResult q2) { 

    object o; 
    if (q1.someprop == "useme") { 
     fillObject(o,q1); 
    } else if (q2.someprop == "useme") { 
     fillObject(o,q2); 
    } 

    return o; 

    function fillObject(object o, qryResult q) { 
     o.prop1 = q.prop1; 
     o.prop2 = q.prop2; 
     o.prop3 = q.prop3; 
    } 


} 

它保持一點清潔。它是否必須是嵌套函數?不,但你可能想這樣做,如果過程函數是唯一需要這樣做的副本。

相關問題