下标(subscript)

使用subscript可以给任意类型(枚举、结构体、类)增加下标功能,有些地方也翻译为:下标脚本
subscript的语法类似于实例方法、计算属性,本质就是方法(函数)

  1. class Point {
  2. var x: Double = 0
  3. var y: Double = 0
  4. subscript(index: Int) -> Double {
  5. set {
  6. if index == 0 {
  7. x = newValue
  8. } else if index == 1 {
  9. y = newValue
  10. }
  11. }
  12. get {
  13. if index == 0 {
  14. return x
  15. } else if index == 1 {
  16. return y
  17. }
  18. return 0
  19. }
  20. }
  21. }
  22. let point = Point()
  23. point[0] = 1
  24. point[1] = 2
  25. let x = point[0]
  26. let y = point[1]
  27. print(x, y) // 1.0 2.0

给point添加下标,point[0]就是给x赋值,point[1]就是给y赋值。
subscript中定义的返回值类型决定了:

  • get方法的返回值类型
  • set方法中的newValue的类型

subscript可以接收多个参数,并且类型人意

下标的细节

1、subscript可以没有set方法,但必须要有get方法

  1. class Point {
  2. var x: Double = 0
  3. var y: Double = 0
  4. subscript(index: Int) -> Double {
  5. get {
  6. if index == 0 {
  7. return x
  8. } else if index == 1 {
  9. return y
  10. }
  11. return 0
  12. }
  13. }
  14. }

2、如果只有get方法,可以省略get

  1. class Point {
  2. var x: Double = 0
  3. var y: Double = 0
  4. subscript(index: Int) -> Double {
  5. if index == 0 {
  6. return x
  7. } else if index == 1 {
  8. return y
  9. }
  10. return 0
  11. }
  12. }

3、可以设置参数标签

  1. class Point {
  2. var x: Double = 0
  3. var y: Double = 0
  4. subscript(index i: Int) -> Double {
  5. if i == 0 {
  6. return x
  7. } else if i == 1 {
  8. return y
  9. }
  10. return 0
  11. }
  12. }
  13. var p = Point()
  14. print(p[index: 0], p[index: 1]) // 0.0 0.0

添加参数标签后,使用下标时,需要书写参数标签。
4、下标可以是类型方法

  1. class Sum {
  2. static subscript(v1: Int, v2: Int) -> Int {
  3. v1 + v2
  4. }
  5. }
  6. print(Sum[10, 20]) // 30

结构体、类作为返回值对比

  1. struct Point {
  2. var x = 1, y = 2
  3. }
  4. class PointManager {
  5. var point = Point()
  6. subscript(index: Int) -> Point {
  7. set { point = newValue}
  8. get { point }
  9. }
  10. }
  11. var pm = PointManager()
  12. pm[0].x = 10
  13. pm[0].y = 20
  14. print(pm[0].x, pm[0].y) // 10 20

pm[0].x = 10这行代码,在外部传入的时int类型的数据,但是set方法里接收的是point类型,原因是pm[0].x = 10相当于:

  1. pm[0] = Point(x: 10, y: pm[0].y)

如果Point是类,可以省略下标中的get方法:

  1. class Point {
  2. var x = 1, y = 2
  3. }
  4. class PointManager {
  5. var point = Point()
  6. subscript(index: Int) -> Point {
  7. get { point }
  8. }
  9. }
  10. var pm = PointManager()
  11. pm[0].x = 10
  12. pm[0].y = 20
  13. print(pm[0].x, pm[0].y)

原因是类是引用类型,get方法返回的是指针,所以可以直接修改对应的x和y的值。

接收多个参数的下标

  1. class Grid {
  2. var data = [
  3. [0, 1, 2],
  4. [3, 4, 5],
  5. [6, 7, 8]
  6. ]
  7. subscript(row: Int, column: Int) -> Int {
  8. set {
  9. guard row >= 0 && row <= 3 && column >= 0 && column <= 3 else {
  10. return
  11. }
  12. data[row][column] = newValue
  13. }
  14. get {
  15. guard row >= 0 && row <= 3 && column >= 0 && column <= 3 else {
  16. return 0
  17. }
  18. return data[row][column]
  19. }
  20. }
  21. }
  22. var grid = Grid()
  23. grid[0, 1] = 111
  24. grid[1, 0] = 222
  25. grid[2, 2] = 333
  26. print(grid.data)

打印结果:

  1. [[0, 111, 2], [222, 4, 5], [6, 7, 333]]