下标
Swift 是允许我们自定义下标的。这不仅包含了对自己写的类型进行下标自定义,也包括了对那些已经支持下标访问的类型 (没错就是Array
和 Dictionary
) 进行扩展。我们重点来看看向已有类型添加下标访问的情况吧,比如说Array
。很容易就可以在 Swift 的定义文件 (在 Xcode 中通过 Cmd + 单击任意一个 Swift 内建的类型或者函数就可以访问到) 里,找到Array
已经支持的下标访问类型:
public subscript(index: Int) -> Element
public subscript(bounds: Range<Int>) -> ArraySlice<Element>
共有两种,它们分别接受单个Int
类型的序号和一个表明范围的 Range<Int>
,作为对应,返回值也分别是单个元素和一组对应输入返回的元素。
于是我们发现一个挺郁闷的问题,那就是我们很难一次性取出某几个特定位置的元素,比如在一 个数组内,我想取出 index 为 0, 2, 3 的元素的时候,现有的体系就会比较吃力。我们很可能会要去枚举数组,然后在循环里判断是否是我们想要的位置。其实这里有更好的做法,比如说可以实现一个接受数组作为下标输入的读取方法:
extension Array {
//subscript 下标
subscript (input:[Int]) -> ArraySlice<Element> {
get {
var result = ArraySlice<Element>()
for i in input {
assert(i < self.count, "Index out of range")
result.append(self[i])
}
return result
}
set {
for (index, i) in input.enumerated() {
assert(i < self.count, "Index out of range")
self[i] = newValue[index]
}
}
}
}
这样,我们的 Array
的灵活性就大大增强了:
var arr = [1,2,3,4,5]
arr[[0,2,3]] = [-1,-3,-4]
print(arr) //[-1, 2, -3, -4, 5]
可变参数列表
在 Swift 中写一个可变参数的函数只需要在声明参数时在类型后面加上 ...
就可以了,比如声明一个接受可变参数的 Int
累加函数,当然你可以用传统的for...in
做累加,但是这里我们选择一种看起来更Swift的方式:
func sum(_ input: Int...) -> Int {
return input.reduce(0, +)
}
print(sum(1,2,3,4,5)) //15
可变参数在参数列表中的位置在Swift中是没有限制的,因为我们会对方法的参数进行命名,所以我们可以随意地放置可变参数的位置,而不必拘泥于最后一个参数。
func myFunc(numbers: Int..., string: String) {
numbers.forEach {
for i in 0..<$0 {
print("\(i+1): \(string)")
}
}
}
myFunc(numbers:1,2,3, string:"hello")
//1: hello
//1: hello
//2: hello
//1: hello
//2: hello
//3: hello
当然限制自然是有的,比如在同一个方法中只能有一个参数是可变的,比如可变参数都必须是同一种类型的等。对于后一个限制,当我们想要同时传入多个类型的参数时就需要做一些变通。比如 -stringwithFormat:
方法。可变参数列表的第一个元素是等待格式化的字符串,在 Swift 中这会对应一个 String
类型,而剩下的参数应该可以是对应格式化标准的任意类型。一种解决方法是使用 Any
作为参数类型,然后对接收到的数组的首个元素进行特殊处理。不过因为 Swift 提供了使用下划线 _
来作为参数的外部标签,来使调用时不再需要加上参数名字。我们可以利用这个特性,在声明方法时就指定第一个参数为一个字符串,然后跟一个匿名的参数列表, 这样在写起来的时候就 "好像" 是所有参数都是在同一个参数列表中进行的处理,会好看很多。比如 Swift 的 `NSString` 格式化的声明就是这样处理的:
extension NSString {
convenience init(format: NSString, _ args: CVarRrgType...)
//...
}
调用的时候就和 Objective-C几乎是一样了,非常方便:
let name = "Tom"
let date = NSDate()
let string = NSString(format: "Hello %@. Date: %@", name, date)