Swift: Swift 返回值与函数类型:多返回值、嵌套函数与类型别名

函数不仅能返回基本类型,还能返回多个值、甚至返回另一个函数。本课带你探索 Swift 函数返回值的各种可能,以及函数作为一等公民的核心概念。

1. 你将学到


2. 一个电商开发者的真实故事

(1) 痛点:不同折扣策略需要重复写多个函数

Charlie 在开发一个促销引擎,不同用户等级享受不同折扣:

SWIFT
func vipDiscount(_ price: Double) -> Double {
    return price * 0.8
}
func memberDiscount(_ price: Double) -> Double {
    return price * 0.9
}
func normalDiscount(_ price: Double) -> Double {
    return price
}

每次新增折扣类型就得写一个新函数,促销规则一变又要改一堆代码。策略切换靠手写 if-else,无法动态配置。

(2) 函数作为类型的解法

Swift 中函数是"一等公民",可以像 Int/String 一样被传递和存储:

SWIFT
// 定义折扣策略类型
typealias DiscountStrategy = (Double) -> Double
// 使用函数字典代替 if-else
let strategies: [String: DiscountStrategy] = [
    "vip": { $0 * 0.8 },
    "member": { $0 * 0.9 },
    "normal": { $0 }
]
// 一行切换策略
func applyDiscount(_ price: Double, level: String) -> Double {
    return strategies[level]?(price) ?? price
}

(3) 收益:策略可配置、代码可扩展

维度 改造前 改造后
新增折扣 写新函数 + 改 if-else 添加字典条目
策略切换 if-else 硬编码 按 key 动态选择
复用性 各策略独立,无法组合 函数可组合、可传递
测试覆盖 每策略写测试 统一测试框架

3. 多返回值与函数重载

(1) 使用元组返回多个值

Swift 的元组让函数可以一次性返回多个值:

100%
graph LR
    A[函数返回元组] --> B[元素 1]
    A --> C[元素 2]
    A --> D[元素 3]
    B --> E["命名访问: result.name"]
    C --> F["命名访问: result.age"]
    D --> G["下标访问: result.0"]
方式 语法 适用场景
匿名元组 -> (Int, String) 简单组合,不关心名称
命名元组 -> (sum: Int, avg: Double) 需语义化访问各字段
可选元组 -> (Int, String)? 函数可能失败返回 nil

▶ 示例:数组统计分析

SWIFT
// ============================================
// 返回多个统计值:使用命名元组
// ============================================
func analyze(_ numbers: [Int]) -> (count: Int, sum: Int, average: Double) {
    let count = numbers.count
    let sum = numbers.reduce(0, +)
    let average = count > 0 ? Double(sum) / Double(count) : 0
    return (count, sum, average)
}
let result = analyze([85, 90, 78, 92, 88])
print("总数:\(result.count)")
print("总和:\(result.sum)")
print("平均:\(result.average)")

输出:

TEXT 📖 仅展示
总数:5
总和:433
平均:86.6

(2) 函数重载

Swift 支持多个同名函数,只要参数类型或数量不同:

SWIFT
func area(width: Double, height: Double) -> Double {
    return width * height
}
func area(radius: Double) -> Double {
    return Double.pi * radius * radius
}
print("矩形面积:\(area(width: 10, height: 5))")
print("圆形面积:\(area(radius: 3))")

输出:

TEXT 📖 仅展示
矩形面积:50.0
圆形面积:28.274333882308138

4. 函数作为类型

(1) 函数类型语法

每个函数都有特定的类型,由参数类型和返回值类型决定:

函数签名 函数类型
func add(a: Int, b: Int) -> Int (Int, Int) -> Int
func log() -> Void () -> Void() -> ()
func greet(_ name: String) (String) -> Void
func double(_ n: Int) -> Int (Int) -> Int
💡 注意: 函数类型只包含参数类型和返回值类型,不包含参数标签

▶ 示例:函数作为变量和参数

SWIFT
// ============================================
// 函数作为变量传递和参数传递
// ============================================
// 1. 定义两个简单函数
func add(_ a: Int, _ b: Int) -> Int { return a + b }
func multiply(_ a: Int, _ b: Int) -> Int { return a * b }
// 2. 函数类型变量
var operation: (Int, Int) -> Int = add
print("add: \(operation(3, 4))")
// 3. 切换函数
operation = multiply
print("multiply: \(operation(3, 4))")
// 4. 函数作为参数
func execute(_ a: Int, _ b: Int, using op: (Int, Int) -> Int) -> Int {
    return op(a, b)
}
print("execute add: \(execute(5, 6, using: add))")
print("execute multiply: \(execute(5, 6, using: multiply))")

输出:

TEXT 📖 仅展示
add: 7
multiply: 12
execute add: 11
execute multiply: 30

(2) typealias 为函数类型命名

当函数类型较复杂或在多处使用时,用 typealias 取别名:

SWIFT
// 定义函数类型别名
typealias IntOperation = (Int, Int) -> Int
// 使用别名声明变量和参数
func calculate(_ a: Int, _ b: Int, using op: IntOperation) -> Int {
    return op(a, b)
}
let op: IntOperation = { $0 * $0 + $1 * $1 }
print("计算:\(calculate(3, 4, using: op))")

输出:

TEXT 📖 仅展示
计算:25

5. 嵌套函数与函数返回函数

(1) 嵌套函数

函数内部可以再定义函数,内层函数只能在外层函数作用域内访问:

SWIFT
// ============================================
// 嵌套函数:在函数内部定义辅助函数
// ============================================
func formatFullName(first: String, last: String) -> String {
    // 嵌套辅助函数
    func capitalize(_ text: String) -> String {
        return text.prefix(1).uppercased() + text.dropFirst().lowercased()
    }
    return "\(capitalize(first)) \(capitalize(last.uppercased()))"
}
print(formatFullName(first: "alice", last: "JOHNSON"))

输出:

TEXT 📖 仅展示
Alice Johnson

(2) 函数返回函数

高阶函数的另一种形式——返回一个函数:

SWIFT
// ============================================
// 函数工厂:根据参数生成不同策略函数
// ============================================
func makeMultiplier(factor: Double) -> (Double) -> Double {
    func multiplier(_ value: Double) -> Double {
        return value * factor
    }
    return multiplier
}
let double = makeMultiplier(factor: 2)
let triple = makeMultiplier(factor: 3)
print("double(5) = \(double(5))")
print("triple(5) = \(triple(5))")

输出:

TEXT 📖 仅展示
double(5) = 10.0
triple(5) = 15.0

▶ 示例:折扣策略工厂

SWIFT
// ============================================
// 使用嵌套函数和函数返回值实现折扣工厂
// ============================================
typealias DiscountRule = (Double) -> Double
func discountFor(level: String) -> DiscountRule? {
    // 嵌套函数定义各等级折扣
    func vip(_ price: Double) -> Double { return price * 0.8 }
    func member(_ price: Double) -> Double { return price * 0.9 }
    func normal(_ price: Double) -> Double { return price }
    switch level {
    case "vip": return vip
    case "member": return member
    case "normal": return normal
    default: return nil
    }
}
if let rule = discountFor(level: "vip") {
    print("VIP 折扣后:$\(rule(100))")
}

输出:

TEXT 📖 仅展示
VIP 折扣后:$80.0

6. 完整示例:促销引擎

SWIFT
// ============================================
// 完整示例:促销引擎
// 功能:多返回值 + 函数类型 + typealias + 嵌套函数
// ============================================
import Foundation
// 1. 定义函数类型别名
typealias Discount = (Double) -> Double
typealias DiscountResult = (original: Double, final: Double, saved: Double)
// 2. 折扣工厂——返回嵌套函数
func createDiscount(minSpend: Double, rate: Double) -> Discount {
    func discount(_ price: Double) -> Double {
        return price >= minSpend ? price * (1 - rate) : price
    }
    return discount
}
// 3. 多返回值——返回折扣结果详情
func applyDiscount(price: Double, rule: Discount) -> DiscountResult {
    let final = rule(price)
    let saved = price - final
    return (price, final, saved)
}
// 4. 函数作为参数——批量处理订单
func processOrders(_ prices: [Double], using rule: Discount) -> [DiscountResult] {
    return prices.map { applyDiscount(price: $0, rule: rule) }
}
// 5. 使用促销引擎
let memberRule = createDiscount(minSpend: 50, rate: 0.15)
let orderResults = processOrders([120, 45, 200], using: memberRule)
for result in orderResults {
    print("$\(result.original) → $\(result.final)(节省 $\(result.saved))")
}

输出:

TEXT 📖 仅展示
$120.0 → $102.0(节省 $18.0)
$45.0 → $45.0(节省 $0.0)
$200.0 → $170.0(节省 $30.0)

❓ 常见问题

Q 函数类型为什么忽略参数标签?
A 函数类型聚焦于类型匹配——参数和返回值的类型。标签属于外部调用约定,不影响类型兼容性。因此 (a: Int) -> Void(b: Int) -> Void 是同一类型。
Q 嵌套函数和闭包有什么区别?
A 嵌套函数是有名字的内层函数,闭包通常是匿名的代码块。嵌套函数可以捕获外层变量,行为上与闭包类似,但有名字、可重复调用。
Q typealias 可以用于复杂的泛型函数类型吗?
A 可以。例如 typealias Transformer<T> = (T) -> T 定义一个泛型函数类型别名。但 Swift 中 typealias 不能直接关联泛型约束,需用其他方式实现。
Q 返回元组和返回自定义结构体哪个更好?
A 简单组合用元组(如返回两个 Int),语义复杂的场景用结构体(有名字段有名称和文档)。元组适合临时组合,结构体适合公共 API。
Q 函数重载会导致运行时性能下降吗?
A 不会。函数重载在编译时就确定了调用哪个版本(静态派发),没有运行时开销。Swift 编译器根据参数类型和数量在编译期做选择。

📖 小节


📝 作业

  1. 基础题: 写一个 divide(_:_:) 函数,返回商和余数(使用元组)。调用并打印 divide(17, 5) 的结果。
  2. 进阶题:Int 数组写一个 transform 函数,接收一个 (Int) -> Int 类型的参数,返回新数组。然后使用 typealias 定义该函数类型的别名。
  3. 挑战题: 实现一个"运算链"——写一个函数 chain(_:_:),接收一个初始值 Int 和一个函数数组 [(Int) -> Int],依次将每个函数应用于初始值并返回最终结果。然后创建三个转换函数并组成链。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏