默认参数、可变参数与 in-out
本教程共 93 篇 · 第 30 篇 · 更新于 2026-08-08 · 约 9 分钟阅读
本节目标:学会给参数设默认值、用可变参数接收任意数量的实参,以及用 in-out 参数让函数直接修改外部变量的值。
基础的函数参数每次调用都得传齐。Swift 提供了三种机制让参数更“善解人意”:默认值让你能省着传,可变参数让你传任意多个,in-out 让你能改外面的变量。这一章把这三种都讲明白。
1-1 默认参数值
给参数在类型后面直接赋值,它就有了默认值。调用时可以不传这个参数,函数体内就用默认值。
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
print("必填=\(parameterWithoutDefault),默认=\(parameterWithDefault)")
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6)
someFunction(parameterWithoutDefault: 4)
第一次显式传 6,第二次省略,于是 parameterWithDefault 取 12。默认值把“常用场景”固化进函数,调用处更短。
Tip一个重要的排布规则:把没有默认值的参数放在前面,有默认值的放在后面。因为 Swift 不支持“跳过前面的、只传后面的”这种乱序传参,默认值参数放后面才能保证省略时不会让位置错乱。写函数时养成这个顺序习惯,调用者才不会踩坑。
1-2 可变参数
可变参数(variadic parameter)能接收零个或多个同类型的值,写法是在类型后面加三个点 ...。
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
print(arithmeticMean(1, 2, 3, 4, 5))
print(arithmeticMean(3, 8.25, 18.75))
numbers 在函数体内表现为一个 [Double] 数组,你照常遍历它。这样函数就能算任意长度数字的平均值,调用时想传几个传几个。
Note一个函数可以有多个可变参数。但可变参数后面的参数必须带标签——否则编译器分不清哪些实参属于可变参数、哪些属于后面的参数。标签在这里起到了“边界标记”的作用。
1-3 in-out 参数:让函数改外面的变量
默认情况下,函数参数是常量,想在函数里改它的值会编译报错。这能防止你无意中改坏传入的值。但有时你就是想让函数“就地修改”外部变量,这时用 inout 关键字。
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt=\(someInt), anotherInt=\(anotherInt)")
swapTwoInts 把两个变量的值互换。注意调用时变量名前加了 &,表示“这个变量允许被函数修改”。传入的必须是变量(var),不能是常数或字面量,因为常量和字面量没法被改。
Warningin-out 参数有两条硬约束:不能设默认值,也不能是可变参数(
variadic)。另外要清醒地知道,in-out 和“返回值”是两码事——上面的交换函数没有返回类型,却实打实地改了someInt和anotherInt。它是函数“在函数体之外产生副作用”的另一种途径。
1-4 in-out 和返回值的取舍
什么时候用 in-out,什么时候用返回值?粗略地说:如果只是想拿结果,返回值更清晰、更函数式;如果修改的是调用者已经持有的那个变量、且语义上就是“就地改”,in-out 更自然,比如交换、累加、配置对象属性。
func addBonus(_ score: inout Int) {
score += 100
}
var playerScore = 50
addBonus(&playerScore)
print(playerScore) // 150
这里 playerScore 是调用者手里的变量,addBonus 直接给它加分,符合“就地改”的直觉。如果换成返回 score + 100 再让调用者自己赋值,也完全可以,选哪种看你想强调“产生新值”还是“修改旧值”。
1-5 三种参数一起用
它们并不冲突,可以组合在一个函数里:
func configure(name: String, fontSize: Int = 14, options: String...) {
print("名称=\(name),字号=\(fontSize),选项=\(options)")
}
configure(name: "标题")
configure(name: "正文", fontSize: 16, options: "加粗", "居中")
name 必填,fontSize 有默认值,options 是可变参数。组合起来,函数既能简单调用,也能在需要时给足细节。这种灵活度正是 Swift 函数语法的强项。
Note组合时仍要遵守顺序:必填参数在前,默认值参数居中,可变参数通常放最后(它后面不能再有不带标签的参数)。顺序对了,调用处才不会歧义。
1-6 三种参数放在一起怎么记
给三种参数各配一句口诀,不容易混:默认参数管“省事”——常用值我替你填好;可变参数管“不定”——你传几个我都收进数组;in-out 管“可变”——你给我一个变量,我改完还给你。它们解决的问题完全不同,所以可以同时出现在一个函数里,互不打架。
要提醒的是,in-out 是“改你已有的”,返回值是“给你新的”。初学者有时会纠结“到底用哪个”。一个判断:如果调用者本来就持有一个要被更新的状态(比如计数器、配置),用 in-out 更顺;如果只是想算个结果,老老实实返回值更清晰,也更容易测试。两者不是竞争关系,按语义取用即可。
1-7 一个常见误用:滥用 in-out
初学者有时图方便,把本该返回结果的参数也设成 in-out,导致函数既返回值又改入参,职责不清。好的习惯是:要么返回新值,要么用 in-out 就地改,二选一,别同时来。
另外,in-out 参数传的是“变量的引用”,函数内部对它做的修改会在函数结束后保留。这意味着调用者传入的变量在函数返回后可能已变。用之前想清楚:你真的希望这个变量被改吗?如果不确定,优先返回值,副作用更小、更容易推理。
还有一点:默认参数和可变参数不要堆在同一函数上到让人看不懂。参数列表越长越灵活,但可读性也在下降。当参数多到需要靠默认值来“救场”时,往往说明这个函数该拆了。保持参数精炼,是函数好用的前提。
实际项目里,in-out 最典型的例子就是标准库里的原地排序 sort()——它直接改调用者的数组,返回值反而多余。理解了这一点,你就明白 in-out 不是炫技,而是“就地修改”语义的自然表达。
默认值让常用调用更短,可变参数让数量不定成为可能,in-out 让函数能改外部状态。三者都是为了减少调用者的负担、让函数接口更贴合实际使用。下一章我们看“函数类型”——函数本身也有类型,可以作为值传来传去,那是 Swift 函数真正厉害的地方。