首页 / Swift 编程语言教程 / 函数类型

Swift 编程语言教程

函数类型

本教程共 93 篇 · 第 31 篇 · 更新于 2026-08-08 · 约 9 分钟阅读

SwiftSwift 编程语言教程函数类型function type高阶函数函数作为参数函数作为返回值类型推断

本节目标:理解函数本身也有类型,能把函数存进变量、当作参数传递、当作返回值返回,体会“函数是一等公民”的含义。

你可能习惯了“整数有 Int 类型、文字有 String 类型”。但 Swift 里函数也有类型。一个函数的类型,由它的“参数类型”和“返回类型”共同决定。正因为函数是带类型的,它才能像普通值一样被赋值、被传递。这是 Swift 函数最强大、也最容易被初学者忽略的一点。

1-1 函数类型的长相

看两个函数:

func addTwoInts(_ a: Int, _ b: Int) -> Int {
    return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
    return a * b
}

它们都吃两个 Int、返回一个 Int,所以类型都是 (Int, Int) -> Int。读法是:“一个接收两个 Int、返回 Int 的函数”。类型只关心参数的类型和返回类型,不关心函数叫什么名字、内部怎么实现

func printHelloWorld() {
    print("你好,世界")
}

这个函数没参数也没返回值(即返回 Void),它的类型是 () -> Void

1-2 把函数赋给变量

因为函数有类型,你就能声明一个“函数类型的变量”,把函数存进去,之后用变量名来调用。

var mathFunction: (Int, Int) -> Int = addTwoInts
print("结果:\(mathFunction(2, 3))")   // 5

mathFunction 被声明为 (Int, Int) -> Int 类型,然后指向 addTwoInts。之后调 mathFunction(2, 3) 就等于调 addTwoInts。同一类型的另一个函数也能赋给同一个变量:

mathFunction = multiplyTwoInts
print("结果:\(mathFunction(2, 3))")   // 6

这不就是普通的值替换嘛——只要类型匹配,换哪个函数都行。和给 Int 变量重新赋值没有本质区别。

Tip

赋值给变量时,Swift 一般能推断出函数类型,你常可以省略显式标注:let another = addTwoInts。但当你想明确“这里存的是某种函数”,写上类型更清楚,也让编译器帮你检查后面赋的值是否匹配。

1-3 函数作为另一个函数的参数

函数类型可以当作“参数类型”使用。也就是说,一个函数能接收“另一个函数”当输入。这把“具体怎么做”交给调用者决定。

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("结果:\(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)   // 8

printMathResult 的第一个参数类型是 (Int, Int) -> Int,调用时把 addTwoInts 传进去。至于这个数学函数具体是加是乘,printMathResult 根本不关心,它只管“拿到函数就调用”。这种“把行为当参数”的写法,是很多通用工具函数的基石。

Note

这类函数常被称为“高阶函数”(higher-order function)。你以后会大量见到:集合的 mapfiltersorted 都接收一个函数当参数,决定“怎么变换”“怎么筛选”“怎么排序”。这一章讲的是它们底层的共同原理。

1-4 函数作为返回值

函数类型也能当作“返回类型”。也就是一个函数可以“生”出另一个函数返回给你。写法是在返回箭头后写完整的函数类型。

func stepForward(_ input: Int) -> Int {
    return input + 1
}
func stepBackward(_ input: Int) -> Int {
    return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
    return backward ? stepBackward : stepForward
}

chooseStepFunction 的返回类型是 (Int) -> Int,意思是“返回一个吃 Int 返回 Int 的函数”。调用它拿到函数后,再拿去用:

var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
while currentValue != 0 {
    print("\(currentValue)... ")
    currentValue = moveNearerToZero(currentValue)
}
print("到零了!")

这里根据 currentValue 是正还是负,挑出“往零靠近”的步进函数。返回的这个函数被存进 moveNearerToZero,后续的循环完全不关心它具体是前进还是后退,只管反复调用。这种“按需定制行为再返回”的模式非常灵活。

1-5 为什么这很重要

把函数当值看待,意味着“行为”也能像数据一样流动。你可以把不同的策略(不同的函数)传来传去,写出更通用、更少重复的代码。面向协议、闭包、异步回调这些高级主题,底层都建立在这个认知上。

Warning

函数类型匹配是“按签名匹配”,不看函数名。两个函数只要参数类型、返回类型一致,就能互相替换,哪怕它们语义完全不同。这既是灵活之处,也要求你传函数时心里清楚“传进去的到底是干什么的”,别只看类型对上就随手塞。

1-6 一个串起来的小例子

把前面几点合起来看:函数类型让“行为”也能当数据。假设你要对一个数字列表做不同统计,可以写一个接收“怎么算”的函数:

func summarize(_ numbers: [Int], using operation: (Int, Int) -> Int) -> Int {
    var result = numbers[0]
    for n in numbers[1...] {
        result = operation(result, n)
    }
    return result
}
let sum = summarize([1, 2, 3, 4], using: addTwoInts)

summarize 不关心具体是加是乘,它只负责“按顺序把操作应用到每个数上”。把 addTwoInts 传进去就求和,传 multiplyTwoInts 就求积。这就是函数作为参数的威力:算法骨架固定,细节由调用者注入,既通用又好测。

1-7 函数类型与类型推断的配合

当你把函数赋给变量时,通常不必写全类型,Swift 能从右侧的函数推断出变量类型。但一旦变量类型确定,后面就只能赋同类型的函数,赋错类型编译器立刻拦下。这种“推断 + 校验”的组合,既省事又安全。

还有一点容易忽略:函数类型只认签名,不认名字。所以 addTwoInts 和任何一个 (Int, Int) -> Int 的函数都能互换,哪怕它叫 plusconcatenateNumbers。理解这点,你就不会惊讶于“为什么随便传个同签名函数都能工作”。这也是高阶函数能通用的底层原因。

正因为函数有类型、能推断、能互换,Swift 才敢让你把函数传来传去。你在标准库里见到的 sorted(by:)filter(_:)reduce(_:_:),本质都是“接收一个函数类型参数”的普通函数。本章讲的原理,正是它们能成立的土壤。

当你真正开始写自己的高阶函数时,会发现函数类型让“策略”可以参数化:排序策略、比较策略、转换策略都能作为函数传进去,主流程保持不动。这是代码复用的最高形态之一——复用逻辑骨架,替换其中可变的行为。

函数类型初看抽象,但用上个两三次就会觉得理所当然——它只不过把“函数能做啥”也变成了一个可以写明、可以传递的东西。一旦这个概念落地,后面的闭包、异步回调都会顺理成章。

理解函数类型,你就握住了 Swift 函数式写法的钥匙。下一章我们看的“嵌套函数”,会顺带展示函数作为返回值最常见的一种自然用法。