首页 / Swift 编程语言教程 / 嵌套函数

Swift 编程语言教程

嵌套函数

本教程共 93 篇 · 第 32 篇 · 更新于 2026-08-08 · 约 8 分钟阅读

SwiftSwift 编程语言教程嵌套函数nested function作用域函数返回函数闭包前奏封装

本节目标:理解函数内部还能定义函数,知道嵌套函数默认对外隐藏、但能被外层调用或当作返回值带出去,并看清它和闭包的关系。

到目前为止你见到的函数都是“全局函数”,定义在所有代码的最外层,哪里都能调用。Swift 还允许你把函数写在另一个函数的内部,这叫“嵌套函数”(nested function)。它像一层外壳里的工具,默认外面看不见,只在需要时被外层使用或带出去。

1-1 嵌套函数长什么样

就在函数体里再写一个 func 即可:

func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    func stepForward(input: Int) -> Int { return input + 1 }
    func stepBackward(input: Int) -> Int { return input - 1 }
    return backward ? stepBackward : stepForward
}

stepForwardstepBackward 定义在 chooseStepFunction 里面。从外面看,chooseStepFunction 之外根本没法直接调用这两个小函数——它们被“关”在了外层函数的作用域里。

Note

嵌套函数的存在意义,往往是“只服务于外层这一件事”的辅助逻辑。既然别处用不到,藏起来既避免名字污染全局,也让外层函数的意图更聚焦。

1-2 外层能调用,也能返回

嵌套函数虽然对外隐藏,但外层函数内部可以自由调用它。更妙的是,外层函数可以把嵌套函数当作返回值交出去,让它在别的作用域里继续活。

var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("到零了!")

这里 currentValue-4,所以 chooseStepFunction(backward:) 返回了内部的 stepForward。返回的这个函数被存进 moveNearerToZero,随后在循环里反复使用。注意:调用 chooseStepFunction 早就结束了,但被它“带出来”的嵌套函数仍在工作。

Tip

这种“函数生函数、再把函数交出去”的结构,正是闭包的雏形。嵌套函数已经具备“被返回、在别处执行”的能力,等讲到闭包时你会发现,闭包只是把这种写法推到了极致——连完整函数定义都能内联成一段更短的语法。

1-3 作用域与可见性

嵌套函数能访问外层函数的参数和变量吗?能。因为嵌套函数处在外层的作用域之内,它可以看到外层定义的东西。但反过来,外层看不到嵌套函数内部定义的局部变量,全局更看不到嵌套函数本身。

func outer(x: Int) -> Int {
    func inner(y: Int) -> Int {
        return x + y   // inner 能用到外层的 x
    }
    return inner(x)
}

inner 直接用了外层的 x,毫无障碍。这种“内层看得见外层”的层次关系,正是作用域的基本规则。它让嵌套函数天然适合“带着外层上下文去干活”。

1-4 什么时候用嵌套函数

第一,当某段逻辑只服务于一个函数、且这个函数体已经偏长时,把其中一块抽成嵌套函数,主干更清晰。

第二,当需要根据条件动态选择“用哪个实现”,又不想把这些实现暴露到全局时,用嵌套函数 + 返回最自然。

第三,作为学习闭包前的过渡。理解了嵌套函数“能被返回并带上下文”,再学闭包就只是语法糖的差别,心理门槛低很多。

Warning

别滥用嵌套。如果函数嵌套了三四层、每层都定义小函数,阅读者要在层层缩进里跳来跳去,反而更累。一般嵌套一层就够;更深的结构考虑拆成独立函数或闭包。嵌套是工具,不是炫技。

1-5 和闭包的关系一句话点破

闭包本质上就是“能捕获周围变量的匿名函数”。嵌套函数已经能“待在外层作用域、被返回、带着外层变量走”。闭包把“定义”这件事变得更轻:不必专门起个名字、不必写完整函数头,就地写一段能带走上下文的代码即可。所以学嵌套函数,等于提前踩中了闭包的门槛。

1-6 嵌套函数的隔离价值

嵌套函数最大的隐形好处是“命名隔离”。在大型项目里,全局函数越多,名字越容易撞。把一个只服务某个函数的辅助逻辑写成嵌套函数,它就不再占用全局名字空间,外面根本看不见,自然不会和别处的同名函数冲突。

不过要注意,嵌套函数只能在它的外层函数里被调用或被返回。你想从外部直接调它做不到——这既是限制,也是保护:它强迫辅助逻辑和它的主人绑定在一起,不会被人误用到不相干的地方。当辅助逻辑确实只属于某一个函数时,嵌套是最贴切的归宿。

1-7 嵌套函数与递归

嵌套函数也能递归——在它自己内部调用自己。只要逻辑正确(有明确的退出条件),嵌套函数完全可以像普通函数那样递归求解。它只是“住”在外层函数里而已,递归能力和是不是嵌套无关。

再补充一个视角:嵌套函数因为能看见外层参数,常用来实现“带状态的工厂”。外层函数持有一些配置,嵌套函数利用这些配置生成不同行为,再被返回出去。这种“外层给料、内层加工、产物外出”的模式,是闭包和柯里化思想的雏形,值得在学到后面时回看本章。

最后提醒:嵌套函数返回的那些“带走外层变量”的函数,正是闭包的近亲。等你正式学闭包,会发现语法更短,但“带着上下文走”的本质和嵌套函数一模一样。本章就是那块最好的敲门砖。

也有人不喜欢嵌套,理由是缩进深了不好读。这和个人风格有关;只要嵌套层数是一两层,收益(隔离、内聚)通常大于代价。真到了三层以上,才该考虑把函数提到外层单独定义。

掌握嵌套函数,你对“函数可以层层包裹、可以相互返回”就有了实感。下一章我们看函数重载:同名函数靠不同签名共存,这是 Swift 多态最轻量、也最常用的一种形式。