认识Swift系列10之下标(类、结构体、枚举皆可用)

2019-07-12  本文已影响0人  Niuszeng
    // 下标subscript本质就是一个方法
    // 使用下标定义了方法后,外部可以通过中括号[]方式方位setter和getter方法
    // subscript方法的返回值类型决定了set的newValue类型和get方法的返回值类型
    class Point {
        var x = 0.0, y = 0.0, z = 0.0
        subscript(index: Int) -> Double {
            set {
                if index == 0 {x = newValue}
                else if index == 1 {y = newValue}
                else  {z = newValue}
            }
            get {
                if index == 0 {return x}
                else if index == 1 {return y}
                else  {return z}
            }
        }
        
        subscript(index: String) -> Double {
            set {
                if index == "x" {x = newValue}
                else if index == "y" {y = newValue}
                else  {z = newValue}
            }
            get {
                if index == "x" {return x}
                else if index == "y" {return y}
                else  {return z}
            }
        }
        
        func show() {
            print("x == \(x),y == \(y),z == \(z)")
        }
    }
    
    let p = Point()
    p.show()
    
    p[0] = 20
    p[1] = 1
    p[2] = 9
    p.show()
    
    p["x"] = 33
    p["y"] = 44
    p["z"] = 55
    p.show()
    
    
    // subscript可以没有set方法,但是必须要有get方法,只有get的时候,可以省略get
    // 必须有get,可以省略set
    class Size {
        var w = 0.0, h = 0.0
        // 只有get
        /**
         subscript(index: Int) -> Double {
             get {
                 if index == 0 {return w}
                 else  {return h}
             }
         }
         */
        // 只有get可以省略get
        subscript(index: Int) -> Double {
            if index == 0 {return w}
            else  {return h}
        }
        
        func show() {
            print("w == \(w),h == \(h)")
        }
    }
    
    // 可以设置参数标签
    class Point1 {
        var x = 0.0, y = 0.0, z = 0.0
        subscript(indexTag index: Int) -> Double {
            set {
                if index == 0 {x = newValue}
                else if index == 1 {y = newValue}
                else  {z = newValue}
            }
            get {
                if index == 0 {return x}
                else if index == 1 {return y}
                else  {return z}
            }
        }
        func show() {
            print("x == \(x),y == \(y),z == \(z)")
        }
    }
    
    let p1 = Point1()
    p1.show()
    
    p1[indexTag: 0] = 23
    p1[indexTag: 1] = 33
    p1[indexTag: 2] = 43
    p1.show()
    
    // 下标可以传多个参数
    // 下标可以使类方法
    class Point2 {
        static subscript(v1: Int, v2: Int) -> Int {
            v1 + v2
        }
    }
    print(Point2[1, 10])
    
    // 下标返回结构体和类的区别
    // 当结构体类添加下标方法的时候,有适合可能必须加入set方法
    func testStruct() {
        class File {
            var x = 0, y = 0
        }
        class FileManager {
            var f = File()
            subscript(index: Int) ->File { f }
        }
        
        let fm = FileManager();
        fm[0].x = 10
        fm[0].y = 10
        print("class fm f (\(fm.f.x), \(fm.f.y))")
    }
    func testClass() {
        struct File {
            var x = 0, y = 0
        }
        struct FileManager {
            var f = File()
            subscript(index: Int) ->File {
                set {
                    f = newValue
                    // 虽然外部值修改f的x属性,但实际操作是外部会构建新的结构体来进行值覆盖
                }
                get {f}
            }
        }
        
        var fm = FileManager();
        fm[0].x = 10 // f = File(x: 10, y: fm[0].y)
        fm[0].y = 10 // f = File(x: fm[0].x, y: 10)
        // 两句代码虽然是对f成员的x和y赋值,但对于结构体来说实际上是内存中值得copy过程
        // 即 f.x = 10 等价于 f = File(x:10 y:f.y)
        // 因此,fm[0].x = 10实际上需要调用下标方法中的set方法
        // 所以,下标方法必须实现set
        
        print("class fm f (\(fm.f.x), \(fm.f.y))")
    }
    testStruct()
    testClass()
    
    // 接收多个参数的下标
    class Grid {
        static let NotFound = -1
        var data = [
            [0, 1, 2],
            [3, 4, 5],
            [6, 7, 8]
        ]
        
        subscript(row: Int, column: Int)->Int {
            set {
                guard (row >= 0 && row < 3) && (column >= 0 && column < 3) else { return }
                data[row][column] = newValue
            }
            get{
                guard (row >= 0 && row < 3) && (column >= 0 && column < 3) else { return Grid.NotFound }
                return data[row][column]
            }
        }
    }
    
    var g = Grid()
    g[0, 0] = 40
    g[1, 1] = 40
    g[2, 2] = 40
    print(g.data)
上一篇下一篇

猜你喜欢

热点阅读