Swift 函数

函数是把"一段可复用逻辑"打包的基本单位。Swift 的函数特性丰富——参数标签、默认值、可变参数、inout、元组返回、函数类型……本章讲透每一个,并解释 Swift 设计背后的考量。

1. 基本语法

// 基本语法:func 名(参数) -> 返回类型 { 函数体 }
func add(a: Int, b: Int) -> Int {
    return a + b
}

// 调用时必须写出第一个参数名(标签)
print(add(a: 3, b: 5))           // 8

// 没有返回值就省略 -> 或写成 -> Void
func sayHello() {
    print("Hello!")
}
sayHello()

// 多语句函数,返回值用 return
func isEven(n: Int) -> Bool {
    if n % 2 == 0 {
        return true
    }
    return false
}

// 单表达式函数可省略 return(Swift 5+)
func square(_ x: Int) -> Int { x * x }

几个要点:返回类型用 ->;没有返回值省略或写 Void;Swift 5+ 单表达式可省 return(让函数像数学公式一样简洁)。

2. 参数标签:Swift 函数的灵魂

Swift 函数最特别的一点是参数标签。调用时写出标签,让代码读起来像自然语言——这是从 Objective-C 继承的传统,但更克制:

// 参数标签:Swift 函数的灵魂
// 调用时写"标签"让代码像自然语言

// 1. 默认:形参名既是内部名也是外部标签
func greet(name: String) -> String {
    return "Hi, \(name)"
}
greet(name: "小明")              // 调用时写 name

// 2. 用 _ 省略外部标签(让调用更简洁)
func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}
add(2, 3)                       // 没有 a: b:

// 3. 内外名分开:外部名 内部名
func greet(name: String, from city: String) -> String {
    return "\(name) 来自 \(city)"    // 内部用 city
}
greet(name: "小明", from: "北京")      // 外部用 from

// 经典例子:Swift 标准库的 remove(at:)
// [1,2,3].remove(at: 0)  读起来"remove at 0"

三个核心模式:

标准库的 remove(at:)append(contentsOf:) 都是这种风格的典范——读起来像一句话。

3. 默认参数与可变参数

// 默认参数:调用时可省略
func makeCoffee(sugar: Int = 1, milk: Bool = true) -> String {
    return "coffee, sugar=\(sugar), milk=\(milk)"
}

makeCoffee()                              // coffee, sugar=1, milk=true
makeCoffee(sugar: 3)                      // milk 默认 true
makeCoffee(sugar: 0, milk: false)

// 可变参数:同类型任意个,在函数内是数组
func sum(_ numbers: Int...) -> Int {
    var total = 0
    for n in numbers { total += n }
    return total
}

print(sum(1, 2, 3, 4, 5))                 // 15
print(sum())                              // 0

// 注意:一个函数最多一个可变参数,且一般是最后一个

默认参数让函数调用更灵活(同一个函数不同调用形式);可变参数让函数接受任意个相同类型参数,在函数内是数组。注意:一个函数最多一个可变参数,且通常是最后一个位置。

4. inout 参数

Swift 函数参数默认是常量(不能在函数内修改)。要让函数修改外部变量,用 inout,调用时加 &:

// inout:让函数能修改外部变量(类似 C 的指针传参)
func increment(_ n: inout Int) {
    n += 1
}

var count = 0
increment(&count)              // 注意 &
print(count)                   // 1
increment(&count)
print(count)                   // 2

// inout 用于"想要函数修改入参"的场景
// 但 Swift 推荐优先用返回值,inout 只用于性能关键场合

// 经典例子:swap
func swap(_ a: inout Int, _ b: inout Int) {
    let t = a; a = b; b = t
}
var x = 1, y = 2
swap(&x, &y)
print(x, y)                    // 2 1

Swift 推荐优先用返回值而非 inout,因为返回值更清晰、更易测试。inout 主要用于性能关键场合(避免大结构体拷贝)。

5. 多返回值:元组

Swift 没有专门的"多返回值"语法,但元组实现了一样的效果。给元组元素命名,调用方就能用点语法访问:

// 多返回值:用元组
func minMax(_ nums: [Int]) -> (min: Int, max: Int)? {
    guard !nums.isEmpty else { return nil }
    var lo = nums[0], hi = nums[0]
    for n in nums {
        if n < lo { lo = n }
        if n > hi { hi = n }
    }
    return (lo, hi)
}

if let r = minMax([3, 1, 4, 1, 5, 9, 2, 6]) {
    print("min=\(r.min), max=\(r.max)")   // min=1, max=9
}

// @discardableResult:函数有返回值但调用方常忽略,加这个去掉警告
@discardableResult
func updateCounter() -> Int {
    counter += 1
    return counter
}
updateCounter()     // 不接收返回值,无警告

另一个常用注解 @discardableResult 告诉编译器"这个函数有返回值,但调用方忽略也没关系",消除警告。

6. 函数是一等公民

Swift 里函数是类型——可以赋值给变量、作为参数传递、作为返回值。函数类型写作 (参数类型) -> 返回类型:

// 函数也是一等公民:可赋值、传参、返回
func add(_ a: Int, _ b: Int) -> Int { a + b }
func mul(_ a: Int, _ b: Int) -> Int { a * b }

// 函数类型:(Int, Int) -> Int
var op: (Int, Int) -> Int = add
print(op(2, 3))                // 5
op = mul
print(op(2, 3))                // 6

// 函数作为参数(高阶函数)
func compute(_ a: Int, _ b: Int, using f: (Int, Int) -> Int) -> Int {
    return f(a, b)
}
print(compute(2, 3, using: add))   // 5

// 函数作为返回值
func makeMultiplier(factor: Int) -> (Int) -> Int {
    return { n in n * factor }
}
let double = makeMultiplier(factor: 2)
print(double(5))               // 10

这种"函数当数据用"的能力是函数式编程的基础。Swift 的 mapfilterreduce 都依赖它——这些会在数组和闭包章深入讲。

7. 嵌套函数

函数内部还能再定义函数。嵌套函数对外不可见,但能"捕获"外层的变量:

// 嵌套函数:函数里再定义函数
func makeIncrementer(step: Int) -> () -> Int {
    var total = 0
    func inc() -> Int {
        total += step
        return total
    }
    return inc
}

let counter = makeIncrementer(step: 5)
print(counter())               // 5
print(counter())               // 10
print(counter())               // 15

// 嵌套函数能"捕获"外部变量(step、total)
// 这其实是闭包的一种,后面专章讲

这其实是闭包的一种形式。下一章讲完可选类型,再下下章我们专门讲闭包。

8. 函数实战

小结

Swift 函数 = 基本语法 + 参数标签 + 默认/可变/inout 参数 + 元组返回 + 函数类型。其中参数标签是最具 Swift 味道的特性,值得反复品味。下一篇我们看 Swift 真正的杀手锏——可选类型

← 上一篇 Swift 控制流

下一篇 Swift 可选类型

✈️💬