Swift Tips 015 - Using variadic parameters

每天了解一点不一样的 Swift 小知识

代码截图

小笔记

这段代码在说什么

这段代码为 Canvas 类拓展了一个名为 add(_ shapes: Shape...) 的函数,由于不确定函数的入参个数,这里使用了可变参数作为入参,即 Shape...

紧接着,我们定义了 circle, lineA, lineB 等三个图形,并将其添加到名为 canvas 的画布上,最后通过调用 render 方法将其绘制出来。

可变参数是什么

可变参数表示函数可以接受零个或多个值。当调用用可变参数的函数时,可变参数表示这个函数参数可以传入不确定数量的输入值。

开发者只需要在变量类型名后面加上 ... 的方式来定义可变参数。可变参数的参数名称在函数体内部会被当做成包含此类型的数组。例如,一个叫做 shapesShape... 型可变参数,在函数体内可以当做一个叫 shapes[Shape] 型的数组常量。

下面的这个函数用来计算一组任意长度数字的算术平均数:

func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 返回 3.0, 是这 5 个数的平均数。
arithmeticMean(3, 8.25, 18.75)
// 返回 10.0, 是这 3 个数的平均数。

这样做的好处与弊端

回到代码上来说,使用可变数组的好处究竟是什么,我们不妨创建一个不使用可变参数的 API:

extension Canvas {
func add(_ shapes: Shape...) {
shapes.forEach(add)
}
func anotherAdd(_ shapes: [Shape]) {
shapes.forEach(add)
}
}
// ... 代码与截图相同
// 调用可变参数的 API 版本
canvas.add(circle, lineA, lineB)
// 调用数组参数的 API 版本
canvas.anotherAdd([circle, lineA, lineB])

在使用数组参数的 API 时,我们不得不在三个元素外面写一个 [] 来将其转换为数组,这种写法稍显冗余,尤其是只有一个元素的时候,anotherAdd([cirle]) 的写法就显得很蹩脚。

当然这种写法也不是十全十美的,假设我们从某个 API 里获取了一组数据时(例如读取了 plist 里面的某个字段),返回值本身就是数组,此时我们还坚持使用可变参数的话,就变得十分麻烦了,但如果使用数组参数的话,代码将变得十分清晰。

如果你是 SDK 设计者的话,在遇到类似的场景时,不妨为相关 API 设计两个不同的版本 ,一个是可变参数,一个是相关类型的数组,这样从使用体验上一定会更好。

毕竟小孩子才做选择题,成年人当然是全都要!