什么是嵌套函数?它们适用于什么?

时间:2009-02-06 16:52:23

标签: information-hiding nested-function

我从未使用过嵌套函数,但是已经看到过几种语言的引用(以及嵌套类,我认为它们是相关的)。

  • 什么是嵌套函数?
  • 为什么?!?
  • 你可以用嵌套函数做什么,你不能做任何其他方式?
  • 如果没有嵌套函数,你可以用嵌套函数做什么?这很难或不优雅?

我假设嵌套函数只是将所有东西视为对象的工件,如果对象可以包含其他对象,那么它就会跟随。

嵌套函数是否具有作用域(一般来说,我认为语言不同)就像函数内部的变量具有作用域一样?

如果您不确定答案是否与语言无关,请添加您引用的语言。

- 亚当

7 个答案:

答案 0 :(得分:4)

嵌套函数的一个常用用法是closures。在具有一等函数的lexically scoped语言中,可以使用函数来存储数据。 Scheme中的一个简单示例是一个计数器:

(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

在这个例子中,我们将函数计数器嵌入到函数make-counter中,通过返回这个内部函数,我们可以在定义时访问可用于计数器的数据。此信息对于mycounter的此实例是私有的 - 如果我们要创建另一个计数器,它将使用不同的位置来存储内部计数。继续前一个例子:

(define mycounter2 (make-counter))

(mycounter2)                      ; returns 1

(mycounter)                       ; returns 3

答案 1 :(得分: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();
}

上面的代码是完全组成的,但它基于C#来表达我的意思。可以调用NestedGetFiles的唯一方法是GetFiles方法。

答案 2 :(得分:2)

嵌套函数只是另一个函数内的一个函数。

是的,这是一切都是对象的结果。由于变量只能在函数的作用域中可见,变量可以指向函数,因此可以使用由局部变量引用的函数。

我认为你无法用嵌套函数做任何事情,你绝对不能没有。但很多时候它是有意义的。即,只要函数是某个其他函数的“子函数”。

对我来说,一个常见的用例是函数执行许多复杂的逻辑,但函数计算/返回的内容很容易为逻辑所指示的所有情况抽象。

答案 3 :(得分:1)

(C#): 我用它来简化对象浏览器视图,并更好地构建我的类。 正如类Wheel嵌套在Truck类中。

不要忘记这个细节: “嵌套类型可以访问包含类型的私有和受保护成员,包括任何继承的私有或受保护成员。”

答案 4 :(得分: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处理,但这只是一个简单的例子。

答案 5 :(得分:1)

如果需要将函数作为参数传递给另一个函数,它们也很有用。它们对于为工厂函数制作工厂函数也很有用(在Python中):

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

答案 6 :(得分: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;
   }


}

它让事情变得更加清洁。它必须是嵌套函数吗?不,但是如果过程函数是唯一必须执行此复制的过程,则可能需要这样做。