注:本文为自己学习The Swift Programming Language的笔记,其中的例子为引用原书和其他博文或自己原创的。每个例子都会批注一些实践过程中的经验或思考总结。
1.基础
Swift的类、结构体和枚举可以定义下标(subscript),下标主要用来快速访问集合、列表和序列的成员元素。
我们可以为一个类型定义多个下标,还可以定义适当的下标重载来用来根据传递给下标的索引来设定相应的值。下标不一定是一维的,可以定义多维输入参数来满足自定义类型的要求。
2.下标语法
通过下标可以在方括号中传入一个值或几个值来访问类型的实例,方括号写在实例名后面。
定义下标的语法像是实例方法和计算属性语法的结合体,用subscript关键字声明。和实例函数一样,它也有传入参数和返回值类型;和计算属性一样,它可以是只读的也可以是可读可写的,用取值器和构造器实现。基本格式如下:
subscript(index: Int) -> Int {
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
新传入值可以自定义名字,默认仍然是newValue。只有取值器的下标仍然可以省略简写:
subscript(index: Int) -> Int {
// return an appropriate subscript value here
}
下面定义一个乘法表TimesTable结构体,它有只读下标:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
println("six times three is \(threeTimesTable[6])")
// prints "six times three is 18
声明一个乘法表实例threeTimesTable表示下标参数乘以3的结果,方括号内传入被乘数,这样使用下表语法就像调用一个简洁的方法。
3.下标用处
下标的用处就是提供快速访问成员元素的机制,集合、列表和序列尤其经常使用。
比如Swift的Dictionary字典类型为了实现键值对的快速索引就隐式的实现了下标语法,“键”就是传入下标的索引,而下标返回值为字典中索引对应的“值”。
值得注意的是字典中下标返回值类型是可空类型,因为提供的索引可能没有对应值。
4.下标选项
下标可以接收任意数量任意类型的传入参数,也可以返回任意类型的值。下标参数也可以是变量参数(variable parameter)和可变参数(variadic parameter),但不能是inout型参数或者给参数赋默认值。
类和结构体可以根据需要实现任意多个下标,下标重载提供了实现多个下标的方式:不同的传入参数类型或数量可以根据推断调用对应的下标体。
下面例子中定义了一个二维矩阵(Matrix)结构体,它有一个二维下标表示矩阵元素坐标,下标和矩阵中的一维存储数组通过矩阵长宽建立对应关系:
struct Matrix {
let rows: Int, columns: Int
var grid: Double[]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: 0.0)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
Matrix构造函数把一维数组grid的初始值设定为0,indexIsValidForRow检测行列坐标的有效性,下标实现中用到了assert断言,保证行列坐标不会超界。从二维下标到一维数组的映射关系很简单,row * columns + column就是一维数组下标。
声明一个二维矩阵实例,初始化得到全零矩阵就可以对它的元素进行访问或修改,注意二维矩阵下标不要超界否则会报一个运行错误,assert抛出异常。
var matrix = Matrix(rows : 2, columns : 2)
matrix[1, 1] = 2.0
println("matrix[1, 1] = \(matrix[1, 1])")
//prints matrix[1, 1] = 2.0
使用下标时一定要注意界限问题,下面语句会引发异常,输出"assertion failed: Index out of range...":
matrix[2, 2] = 3.0