函数的本质
- 自包含的代码片段,完成一个"任务"。
- 有名字 → 可被重复"调用"。
- 有类型 → 由"参数类型 + 返回类型"组成,可以像 Int、String 一样被赋值、传递、返回。
- 可嵌套 → 在函数内部再定义函数,实现隐藏实现细节。
语法骨架速记
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
限制:
- 一个函数可以有多个可变参,多个可变参只能有一个可以省略标签,其他的需要使用标签传递实参
- 若后面还有参数,必须带标签。
多个可变参
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
├─ 返回值
│ ├─ 无返回
│ ├─ 单值
│ ├─ 多值(元组)
│ └─ 可选元组
├─ 函数类型
│ ├─ 作为变量
│ ├─ 作为参数
│ └─ 作为返回值
└─ 嵌套函数
总结与实战建议
-
把"函数类型"真正当成类型:
写网络层时,可把
(Data) -> Void
的回调类型typealias
成Completion
,一处修改处处生效。 -
默认参数 + 可变参组合:
封装日志库时,
func log(_ items: Any..., separator: String = " ")
既能接收任意数量,又能自定义分隔符。 -
in-out 的替代方案:
多数场景可用返回元组代替,语义更清晰;in-out 仅当"必须原地修改"且"性能敏感"才用。
-
嵌套函数是"小范围私有函数"的最佳实践:
避免全局命名空间污染,尤其在算法题或表格视图控制器里,可把"工具函数"直接嵌套在
viewDidLoad
里。 -
函数式思维:
多利用"函数作为返回值"做策略模式,比传统面向对象的"策略类"更轻量。例如根据用户配置返回不同价格计算器:
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