什么是嵌套函数?它们是做什么用的?
-
22-08-2019 - |
题
我从未使用过嵌套函数,但在多种语言中看到过对它们的引用(以及嵌套类,我认为它们是相关的)。
- 什么是嵌套函数?
- 为什么?!?
- 你可以用嵌套函数做哪些其他方法无法做的事情?
- 你能用嵌套函数做什么,如果没有嵌套函数,这会很困难或不优雅?
我认为嵌套函数只是将所有内容视为对象的产物,如果对象可以包含其他对象,那么它就会随之而来。
嵌套函数是否具有作用域(一般来说,我认为语言在这方面有所不同),就像函数内的变量具有作用域一样吗?
如果您不确定您的答案是否与语言无关,请添加您所引用的语言。
-亚当
解决方案
嵌套函数的一种流行用法是 关闭. 。在一个 词法范围 具有一流函数的语言可以使用函数来存储数据。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
其他提示
当只有 1 个方法调用递归时,它非常有用
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 方法。
嵌套函数只是另一个函数内部的一个函数。
是的,这是一切事物都是对象的结果。由于您可以拥有仅在函数范围内可见的变量,并且变量可以指向函数,因此您可以拥有由局部变量引用的函数。
我不认为使用嵌套函数可以做任何你绝对不能做的事情。不过很多时候这是有道理的。即,每当一个函数是某个其他函数的“子函数”时。
对我来说,一个常见的用例是,一个函数执行大量复杂的逻辑,但该函数计算/返回的内容很容易抽象为该逻辑规定的所有情况。
(C#) :我用它来简化对象浏览器视图,并更好地构建我的类。作为 Wheel 类嵌套在 Truck 类中。
不要忘记这个细节:“嵌套类型可以访问包含类型的私有和受保护成员,包括任何继承的私有或受保护成员。”
嵌套函数允许您封装仅与一个函数的内部工作相关的代码,同时仍然允许您将该代码分离出来以提高可读性或通用性。在某些实现中,它们还允许访问外部范围。在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 来处理,但这只是一个简单的例子。
如果您需要将一个函数作为参数传递给另一个函数,它们也很有用。它们对于为工厂函数创建工厂函数也很有用(在 Python 中):
>>> def GetIntMaker(x):
... def GetInt():
... return x
... return GetInt
...
>>> GetInt = GetIntMaker(1)
>>> GetInt()
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;
}
}
它让事情变得更干净一些。它必须是嵌套函数吗?不,但如果 process 函数是唯一需要执行此复制的函数,您可能希望采用这种方式。