2

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

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

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

嵌套函数是否具有范围(通常,我认为语言对此有所不同)就像函数内的变量具有范围一样?

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

-亚当

4

7 回答 7

4

嵌套函数的一种流行用法是闭包。在具有一流函数的词法范围语言中,可以使用函数来存储数据。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

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

(define mycounter2 (make-counter))

(mycounter2)                      ; returns 1

(mycounter)                       ; returns 3
于 2009-02-06T17:00:27.210 回答
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 方法。

于 2009-02-06T17:00:57.893 回答
2

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

是的,这是一切都是对象的结果。由于您可以拥有仅在函数范围内可见的变量,并且变量可以指向函数,因此您可以拥有一个由局部变量引用的函数。

我不认为你可以用一个你绝对不能没有的嵌套函数做任何事情。不过,很多时候它是有道理的。即,只要一个功能是某个其他功能的“子功能”。

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

于 2009-02-06T17:05:52.533 回答
1

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

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

于 2009-02-06T17:00:08.957 回答
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 来处理,但这只是一个简单的示例。

于 2009-02-06T17:03:09.527 回答
1

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

>>> def GetIntMaker(x):
...   def GetInt():
...     return x
...   return GetInt
... 
>>> GetInt = GetIntMaker(1)
>>> GetInt()
1
于 2009-02-06T17:06:47.493 回答
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;
   }


}

它让事情变得更干净一些。它必须是嵌套函数吗?不,但是如果进程功能是唯一必须执行此副本的功能,您可能希望这样做。

于 2009-02-06T17:11:12.803 回答