Swift 函数完全指南(一)——从入门到嵌套

函数的本质

  1. 自包含的代码片段,完成一个"任务"。
  2. 有名字 → 可被重复"调用"。
  3. 有类型 → 由"参数类型 + 返回类型"组成,可以像 Int、String 一样被赋值、传递、返回
  4. 可嵌套 → 在函数内部再定义函数,实现隐藏实现细节。

语法骨架速记

swift 复制代码
func 函数名(参数列表) -> 返回类型 {
    // 函数体
}

调用:

函数名(实参)

知识点全景图

无参函数

swift 复制代码
// 无输入、无输出(返回 Void)
func sayHelloWorld() {
    print("hello, world")
}
sayHelloWorld()

易错点:调用时也必须写空括号 (),否则编译器会当成"函数引用"而非"调用"。

单参 + 单返回值

swift 复制代码
func greet(person: String) -> String {
    // 字符串插值更 Swifty
    return "Hello, \(person)!"
}
print(greet(person: "Anna"))   // Hello, Anna!

简化写法:单表达式可省 return

swift 复制代码
func greetAgain(person: String) -> String {
    "Hello again, \(person)!"   // 隐式返回
}

多参数

swift 复制代码
func greet(person: String, alreadyGreeted: Bool) -> String {
    alreadyGreeted ? greetAgain(person: person) : greet(person: person)
}
print(greet(person: "Tim", alreadyGreeted: true))

注意:函数名相同但参数列表不同 → 函数重载(Swift 支持)。

无返回值

swift 复制代码
func greet(person: String) {
    print("Hello, \(person)!")
}

细节:

  • 不写 -> Void 与写 -> Void 完全等价。
  • 调用者可使用 _ = 显式忽略返回值,提高代码可读性。

多返回值 → 元组(Tuple)

swift 复制代码
func minMax(array: [Int]) -> (min: Int, max: Int) {
    var curMin = array[0], curMax = array[0]
    for value in array.dropFirst() {
        if value < curMin { curMin = value }
        if value > curMax { curMax = value }
    }
    return (curMin, curMax)
}
let bounds = minMax(array: [8, -6, 2, 109])
print("最小 \(bounds.min) 最大 \(bounds.max)")

可选元组:当数组可能为空时,返回整个元组为 nil

swift 复制代码
func minMaxSafe(array: [Int]) -> (min: Int, max: Int)? {
    guard !array.isEmpty else { return nil }
    ...
}

参数标签(Argument Label)与参数名

swift 复制代码
func greet(person: String, from hometown: String) -> String {
    "Hello \(person), glad you could visit from \(hometown)."
}
// 调用时形成"句子"
print(greet(person: "Bill", from: "Cupertino"))

省略标签:用 _

swift 复制代码
func add(_ a: Int, _ b: Int) -> Int { a + b }
add(2, 3)   // 不再强制写标签

默认参数值

swift 复制代码
func power(_ base: Int, _ exponent: Int = 2) -> Int {
    return (0..<exponent).reduce(1) { partialResult, _ in
        partialResult * base
    }
}
print(power(5))        // 25
print(power(5, 3))     // 125

规则:带默认值的参数放最右边;调用时省略就从右往左省略。

可变参数(Variadic Parameter)

swift 复制代码
func arithmeticMean(_ numbers: Double...) -> Double {
    guard !numbers.isEmpty else { return .nan }
    return numbers.reduce(0, +) / Double(numbers.count)
}
print(arithmeticMean(1, 2, 3, 4, 5))   // 3.0

限制:

  1. 一个函数可以有多个可变参,多个可变参只能有一个可以省略标签,其他的需要使用标签传递实参
  2. 若后面还有参数,必须带标签。

多个可变参

swift 复制代码
func arithmeticMean(_ numbers: Double..., names: String...) -> Double {
    guard !numbers.isEmpty else { return .nan }
    print(names)
    return numbers.reduce(0, +) / Double(numbers.count)
}
print(arithmeticMean(1, 2, 3, 4, 5, names:"a","b"))   // 3.0

in-out 参数:函数内部修改外部变量

swift 复制代码
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    (a, b) = (b, a)   // 元组交换,无需临时变量
}
var x = 3, y = 107
swapTwoInts(&x, &y)   // 调用时加 &
print("x=\(x) y=\(y)") // x=107 y=3

注意:

  • 只能传变量(var),不能传 let 常量或字面量。
  • in-out 与并发不兼容,不能跨 actor 使用。

函数类型:一等公民

swift 复制代码
typealias MathOp = (Int, Int) -> Int
let op: MathOp = (+)   // 系统运算符也是函数
print(op(2,3))         // 5

高阶函数实战:把函数当参数/返回值

swift 复制代码
func printResult(_ f: (Int,Int)->Int, _ a: Int, _ b: Int) {
    print("结果=\(f(a,b))")
}
printResult(+, 4, 5)

返回函数 → 工厂函数

swift 复制代码
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    backward ? { $0 - 1 } : { $0 + 1 }
}
var value = 3
let move = chooseStepFunction(backward: value > 0)
while value != 0 {
    print(value)
    value = move(value)
}

利用闭包简写,省掉嵌套函数写法,但逻辑等价。

嵌套函数(Nested Function)

swift 复制代码
func chooseStepNested(backward: Bool) -> (Int) -> Int {
    func stepForward(i: Int) -> Int { i + 1 }
    func stepBackward(i: Int) -> Int { i - 1 }
    return backward ? stepBackward : stepForward
}

特点:

  • 默认对外部不可见,封装更彻底。
  • 可捕获外层函数的局部变量(闭包特性)。

思维导图(文字版)

text 复制代码
函数
├─ 定义与调用
├─ 参数
│  ├─ 无参 / 多参
│  ├─ 标签与省略
│  ├─ 默认值
│  ├─ 可变参
│  └─ in-out
├─ 返回值
│  ├─ 无返回
│  ├─ 单值
│  ├─ 多值(元组)
│  └─ 可选元组
├─ 函数类型
│  ├─ 作为变量
│  ├─ 作为参数
│  └─ 作为返回值
└─ 嵌套函数

总结与实战建议

  1. 把"函数类型"真正当成类型:

    写网络层时,可把 (Data) -> Void 的回调类型 typealiasCompletion,一处修改处处生效。

  2. 默认参数 + 可变参组合:

    封装日志库时,func log(_ items: Any..., separator: String = " ") 既能接收任意数量,又能自定义分隔符。

  3. in-out 的替代方案:

    多数场景可用返回元组代替,语义更清晰;in-out 仅当"必须原地修改"且"性能敏感"才用。

  4. 嵌套函数是"小范围私有函数"的最佳实践:

    避免全局命名空间污染,尤其在算法题或表格视图控制器里,可把"工具函数"直接嵌套在 viewDidLoad 里。

  5. 函数式思维:

    多利用"函数作为返回值"做策略模式,比传统面向对象的"策略类"更轻量。例如根据用户配置返回不同价格计算器:

swift 复制代码
enum VipLevel { case normal, silver, gold }
func discount(for level: VipLevel) -> (Double) -> Double {
    switch level {
    case .normal:  { $0 }          // 无折扣
    case .silver:  { $0 * 0.9 }    // 9 折
    case .gold:    { $0 * 0.8 }    // 8 折
    }
}
let finalPrice = discount(for: .gold)(100) // 80
相关推荐
HarderCoder1 天前
Swift 中的不透明类型与装箱协议类型:概念、区别与实践
swift
HarderCoder1 天前
Swift 泛型深度指南 ——从“交换两个值”到“通用容器”的代码复用之路
swift
东坡肘子2 天前
惊险但幸运,两次!| 肘子的 Swift 周报 #0109
人工智能·swiftui·swift
胖虎12 天前
Swift项目生成Framework流程以及与OC的区别
framework·swift·1024程序员节·swift framework
songgeb2 天前
What Auto Layout Doesn’t Allow
swift
YGGP2 天前
【Swift】LeetCode 240.搜索二维矩阵 II
swift
YGGP3 天前
【Swift】LeetCode 73. 矩阵置零
swift
非专业程序员Ping4 天前
HarfBuzz 实战:五大核心API 实例详解【附iOS/Swift实战示例】
android·ios·swift
Swift社区5 天前
LeetCode 409 - 最长回文串 | Swift 实战题解
算法·leetcode·swift
YGGP7 天前
【Swift】LeetCode 54. 螺旋矩阵
swift