通常情况下,我们在使用数组(Array)、字典(Dictionary)时,都会使用下标。其实,在swift中,我们可以给类、结构体、枚举等自定义下标。
1 基本使用
struct Vector3 { var x: Double = 0.0 var y: Double = 0.0 var z: Double = 0.0 subscript(index: Int) -> Double? { switch (index) { case 0: return x case 1: return y case 2: return z default: return nil } } subscript(axis: String) -> Double? { switch (axis) { case "x", "X": return x case "y", "Y": return y case "z", "Z": return z default: return nil } } }
我们在结构体中定义了一个subscript,并且这个subscript类似于一个方法,看上去它的类型为 Int -> Double? , String -> Double?。然后在调用的时候,就可以使用"[index]","[string]"的形式取值。
var vector = Vector3(x: 10, y: 20, z: 30) // 可以通过下标来取值 vector[0] // 10 vector["Z"] // 30
以上代码中,我们只可以取值,但是不能使用"[index]","[string]"来赋值。
以上subscript方法中,相当于只写了get方法,我们可以在其中添加set。这样就可以使用"[index]","[string]"来赋值了。
struct Vector3 { var x: Double = 0.0 var y: Double = 0.0 var z: Double = 0.0 subscript(index: Int) -> Double? { get { switch (index) { case 0: return x case 1: return y case 2: return z default: return nil } } set { guard let newValue = newValue else {return} switch (index) { case 0: x = newValue case 1: y = newValue case 2: z = newValue default: () } } } subscript(axis: String) -> Double? { get { switch (axis) { case "x", "X": return x case "y", "Y": return y case "z", "Z": return z default: return nil } } set { guard let newValue = newValue else {return} switch (axis) { case "x", "X": x = newValue case "y", "Y": y = newValue case "z", "Z": z = newValue default: () } } } } var vector = Vector3(x: 10, y: 20, z: 30) vector[0] = 100 vector // x: 100, y: 20, z: 30 vector["y"] = 200 vector // x: 100, y: 200, z: 30
2 多维下标
struct Matrix { var data: [[Double]] let row: Int let col: Int init (row: Int, col: Int) { self.row = row self.col = col data = [[Double]]() for _ in 0 ..< row { let arow = Array(repeating: 0.0, count: col) data.append(arow) } } subscript(x: Int, y: Int) -> Double { get { assert(x >= 0 && x < self.row && y >= 0 && y < self.col, "Index out of range.") return data[x][y] } set { assert(x >= 0 && x < self.row && y >= 0 && y < self.col, "Index out of range.") data[x][y] = newValue } } subscript(x: Int) -> [Double] { get { assert(x >= 0 && x < self.row, "Index out of range") return data[x] } set(vector) { assert(vector.count == self.col, "Column number does not match.") data[x] = vector } } } var matrix = Matrix(row: 2, col: 2) matrix[1, 1] // 0 matrix[1, 1] = 20
matrix[1, 1] // 20
matrix[0] // [0, 0] matrix[1] // [0, 20] matrix[0] = [10, 100] matrix[0] // [10, 100] matrix[1] // [0, 20]
matrix[0][0] // 10
matrix[0][0] = 1000
matrix[0][0] // 1000