Swift中的扩展、协议、泛型

1,110 阅读4分钟

extension

  • 向已有的structenumclass中添加新功能
  • 扩展不能重写已有功能
  • 计算型属性
    extension Int {
        var add: Int {
            return self + 100
        }
    }
    let addition = 3.add
    
  • 构造器和方法
    struct sum {
        var num1 = 100, num2 = 200
    }
    
    extension sum {
    
        // 添加方法
        func updateTemp() {
    
        }
        // 添加可变实例方法
        mutating func update() {
            self.num1 = 300
        }
    
        // 添加新的构造器
        init(x: Int, y: Int) {
            self.num1 = x
            self.num2 = y
        }
    
        // 添加下标方法
        subscript(multtable: Int) -> Int {
            return 100
        }
    }
    
  • 嵌套类型
    extension Int {
        enum calc {
            case add
            case sub
        }
        var print: calc {
            switch self {
            case 0:
                return .add
            case 1:
                return .sub
            default:
                return .add
            }
        }
    }
    
    print(3.print)
    

protocol

  • 协议规定了用来实现某一特定功能所必需的方法和属性
  • protocol中必须指明getset,只读属性用{get}
     enum days {
         case sun,mon,tue
     }
    
     protocol daysOfWeak {
         var mark: Int {get set}
         var result: Bool { get}
         // 在方法中,改变值类型实例
         mutating func show()
     }
    
  • required: 可以保证所有遵循该协议的子类,同样能为构造器提供一个现实的实现或者继承实现
    protocol tcpProtocol {
        init(no: Int)
    }
    
    class mainClass {
        var no: Int
        init(no: Int) {
            self.no = no
        }
    }
    
    class subClass: mainClass,tcpProtocol {
        var no2: Int
    
        init(no: Int, no2: Int) {
            self.no2 = no
            super.init(no: no)
        }
        //因为遵循协议,所以需要require, 因为继承自父类,所以需要override
        required override convenience init(no: Int) {
            self.init(no: no, no2: 2)
        }
    }
    
  • protocol 可以被当做类型来使用
  • extension中实现protocol
    protocol tcpProtocol {
        func ageType() -> String
    }
    class mainClass {
    
    }
    extension mainClass: tcpProtocol {
        func ageType() -> String {
            return ""
        }
    }
    
  • 协议可以继承一个或者多个协议
  • class专属协议
    • 通过class关键字,限制协议只能适配到class类型中
    • class关键字,必须出现在协议的继承列表中的第一个
    protocol tcpProtocol: class {
    	func ageType() -> String
    }
    
  • 协议合成
    • ,&遵循多个协议时的分隔符
      protocol Stname {
          var name: String {get}
      }
      protocol Stage {
          var age: Int {get}
      }
      struct Person: Stname, Stage {
          var name: String
          var  age: Int
      }
      // celebrator 同时遵循Stage和Stname
      func show(celebrator: Stage & Stname) {
          print("\(celebrator.age) + \(celebrator.name)")
      }
      
  • 检查是否遵循协议
    • as?
    let per = Person(name: "1", age: 0)
    // 检查实例是否遵循了某个协议。
    if per is Stage {
        print("per confirm to Stage")
    }
    // 当遵循该协议时返回该协议,否则返回nil
    if let obj = per as? Stage {
      print("per confirm to Stage")
    }
    

泛型

  • 泛型使用占位类型名(<T>), 来代替实际类型,从而避免重复编写代码
  • 函数名后面跟着占位类型名(T),并且用尖括号括起来<T>
  • <T>中的尖括号告诉swift那个T是函数定义的占位类型名,swift不会去查找名为T的实际类型名
    func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
        let temp = a
        a = b
        b = temp
    }
    var num = "123"
    var num2 = "78"
    
    swapTwoValues(&num2, &num)
    
    print("\(num) + \(num2)") // 输出78 + 123
    
  • 定一个泛型栈
    struct Stack<T> {
        var items = [T]()
        mutating func push(_ item: T) {
            items.append(item)
        }
        mutating func pop() -> T {
            return items.removeLast()
        }
    }
    // 原始类型定义中声明的类型参数列表在扩展中可以使用
    extension Stack {
        var topItem: T? {
            return items.isEmpty ? nil : items[items.count - 1]
        }
    }
    
  • 类型约束
    • 指定了一个必须继承自指定类的类型参数,或者遵循一个特定的协议
    func findIndex<T: SomeClass, U: SomeClass>(index: T, array: U) {
    
    }
    
  • associatedtype
    • 关联类型使用关键字associatedtype来定义
      protocol Container {
        associatedtype ItemType
        mutating func append(_ item: ItemType)
        var count: Int { get }
        subscript(i: Int) -> ItemType { get }
      }
      
      struct Stack<T>: Container {
          typealias ItemType = T
      
          var items = [T]()
          mutating func push(_ item: T) {
              items.append(item)
          }
          mutating func pop() -> T {
              return items.removeLast()
          }
          // Container 协议的实现
          mutating func append(_ item: T) {
              self.push(item)
          }
          var count: Int {
              return items.count
          }
          subscript(i: Int) -> T {
              return items[i]
          }
      }
      
    • 在参数列表中,通过where附加定义参数的约束
      extension Array: Container {
      }
      
      // 在参数列表中,通过where附加定义参数的约束
      func allItemMatch<C: Container, C2: Container>(_ someC: C, _ anotherC: C2) -> Bool where C.ItemType == C2.ItemType, C.ItemType: Equatable {
          if someC.count != anotherC.count {
              return false
          }
          for i in 0..<someC.count {
              if someC[i] != anotherC[i] {
                  return false
              }
          }
          return true
      }
      

访问控制

  • public
  • open
    • 只能修饰class,访问权限最高
    • 能在当前模块内被继承,也能在被导入的模块中被继承
    • 能在当前模块内被重写,也能在被导入的模块中重写
  • internal
    • 默认访问限制
    • 别人不能访问该模块源文件中的实体
  • fileprivate
    • 当前文件内可以访问
  • private
    • 只能在当前类访问,离开作用域无法访问
  • 子类和属性等访问权限
    • 子类访问权限不得高于父类
    • 属性、常量、下标访问权限不得高于本类
    • 必要构造器的访问级别必须和本类相同
    • 协议访问权限
    public protocol Container {
        associatedtype ItemType
        // 实现append函数的访问级别也要是public
        mutating func append(_ item: ItemType)
    }
    
    • 类型别名的访问权限小于或者等于它原本的类型