本篇目标
掌握 Swift 函数的定义、参数、返回值,理解闭包的语法与用法,学会使用常用的高阶函数。
一、函数基础
定义函数:
func greet() {
print("Hello, Swift!")
}
greet() // 调用函数带参数:
func greet(name: String) {
print("Hello, \(name)!")
}
greet(name: "Tom")带返回值:
func add(a: Int, b: Int) -> Int {
return a + b
}
let result = add(a: 3, b: 5) // 8多返回值(使用元组):
func minMax(array: [Int]) -> (min: Int, max: Int)? {
guard !array.isEmpty else { return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let result = minMax(array: [3, 1, 5, 2, 4]) {
print(result.min) // 1
print(result.max) // 5
}二、参数标签
Swift 函数参数有外部标签和内部名称。
func greet(person name: String) {
print("Hello, \(name)")
}
greet(person: "Tom")person是外部标签,调用时使用。name是内部名称,函数体内使用。
省略外部标签:
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
add(3, 5) // 不需要写标签使用 `_` 省略:
func greet(_ name: String) {
print("Hello, \(name)")
}
greet("Tom")三、默认参数值
func greet(name: String = "Guest") {
print("Hello, \(name)")
}
greet() // Hello, Guest
greet(name: "Tom") // Hello, Tom四、可变参数
func sum(_ numbers: Int...) -> Int {
var total = 0
for number in numbers {
total += number
}
return total
}
sum(1, 2, 3) // 6
sum(1, 2, 3, 4) // 10可变参数在函数内部当作数组处理。
一个函数只能有一个可变参数。
五、输入输出参数
使用 inout 在函数内部修改外部变量。
func swapValues(_ a: inout Int, _ b: inout Int) {
let temp = a
a = b
b = temp
}
var x = 1
var y = 2
swapValues(&x, &y)
print(x, y) // 2, 1注意:
调用时参数前加
&。inout参数不能有默认值。不能传入常量或字面量。
六、函数类型
函数本身也是一种类型,可以赋值给变量。
func add(a: Int, b: Int) -> Int {
return a + b
}
var mathFunction: (Int, Int) -> Int = add
let result = mathFunction(3, 5) // 8函数作为参数:
func calculate(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
return operation(a, b)
}
let sum = calculate(a: 3, b: 5, operation: add) // 8函数作为返回值:
func chooseFunction(isAdd: Bool) -> (Int, Int) -> Int {
return isAdd ? add : { $0 - $1 }
}七、嵌套函数
函数内部可以定义函数。
func outer(value: Int) -> Int {
func inner(x: Int) -> Int {
return x * 2
}
return inner(x: value) + 1
}
print(outer(value: 5)) // 11用途:
封装只在内部使用的逻辑。
配合闭包使用。
八、闭包基础
闭包是自包含的代码块,可以在代码中传递和使用。
闭包语法:
{ (参数) -> 返回类型 in
代码
}示例:
let greet = { (name: String) -> String in
return "Hello, \(name)"
}
print(greet("Tom")) // Hello, Tom省略类型(类型推断):
let greet = { name in
return "Hello, \(name)"
}省略 return(单表达式):
let greet = { (name: String) -> String in
"Hello, \(name)"
}参数简写:
let add = { $0 + $1 }
print(add(3, 5)) // 8九、尾随闭包
当闭包是函数的最后一个参数时,可以写成尾随闭包。
func performAction(action: () -> Void) {
action()
}
// 普通写法
performAction(action: {
print("执行操作")
})
// 尾随闭包
performAction {
print("执行操作")
}多个闭包参数:
func load(success: () -> Void, failure: () -> Void) {
// ...
}
load {
print("成功")
} failure: {
print("失败")
}十、逃逸闭包与非逃逸闭包
非逃逸闭包(默认):闭包在函数返回前执行完毕。
func perform(action: () -> Void) {
action()
}逃逸闭包:闭包可能在函数返回后执行,需要加 @escaping。
var completionHandlers: [() -> Void] = []
func addCompletion(handler: @escaping () -> Void) {
completionHandlers.append(handler)
}常见逃逸场景:
异步回调
存储闭包属性
网络请求完成回调
func fetchData(completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
// 模拟网络请求
let data = "服务器返回的数据"
DispatchQueue.main.async {
completion(data)
}
}
}十一、自动闭包
@autoclosure 把表达式自动包装成闭包。
func log(_ message: @autoclosure () -> String) {
print(message())
}
log("这是一条日志") // 不需要写 { }注意:
自动闭包让调用更简洁。
不要滥用,会影响可读性。
十二、常用高阶函数
map:对每个元素做转换。
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
print(doubled) // [2, 4, 6, 8, 10]filter:筛选符合条件的元素。
let evenNumbers = numbers.filter { $0 % 2 == 0 }
print(evenNumbers) // [2, 4]reduce:把数组归约为一个值。
let sum = numbers.reduce(0) { $0 + $1 }
print(sum) // 15
let sum2 = numbers.reduce(0, +)
print(sum2) // 15sorted:排序。
let sorted = numbers.sorted { $0 > $1 }
print(sorted) // [5, 4, 3, 2, 1]compactMap:过滤 nil 并转换。
let strings = ["1", "2", "abc", "4"]
let numbers2 = strings.compactMap { Int($0) }
print(numbers2) // [1, 2, 4]flatMap:展平嵌套数组。
let nested = [[1, 2], [3, 4], [5]]
let flat = nested.flatMap { $0 }
print(flat) // [1, 2, 3, 4, 5]十三、避坑指南
闭包循环引用:闭包捕获 self 时注意使用
[weak self]。@escaping 不要漏写:异步回调必须加。
尾随闭包可读性:闭包较长时,适当换行。
$0、$1 简写:参数多时不建议用,影响可读性。
map 与 forEach 区别:map 有返回值,forEach 没有。
reduce 初始值:不要忘记传初始值。
十四、检查清单
[ ] 能定义带参数和返回值的函数
[ ] 理解参数标签与内部名称
[ ] 会使用默认参数、可变参数、inout 参数
[ ] 理解函数类型
[ ] 会写闭包,掌握简写形式
[ ] 理解尾随闭包、逃逸闭包
[ ] 会使用 map、filter、reduce