美文网首页Swift基础
【Swift进阶笔记】泛型

【Swift进阶笔记】泛型

作者: BeethOven | 来源:发表于2022-03-02 18:47 被阅读0次
    image.png

    泛型类型

    可选类型是泛型

     enum Optional<Wrapped>  {
        case none
        case some(Wrapped)
    }
    

    Array, Dictionary, Set也是泛型,如果不指定类型,系统默认为Any类型

    @frozen public struct Array<Element> {
    }
    
    @frozen public struct Dictionary<Key, Value> where Key : Hashable {
    }
    
    @frozen public struct Set<Element> where Element : Hashable {
    }
    
    var arr = ["1", 2] as [Any]
    

    扩展类型泛型

    • 添加一个使用 Element 作为参数的便利初始化方法 (convenience initializer)
    enum BinaryLeef<Element> {
        case leaf
        indirect case node(Element, l: BinaryLeef<Element>, r: BinaryLeef<Element>)
    }
    
    extension BinaryLeef {
        init(_ value: Element) {
            self = .node(value, l: .leaf, r: .leaf)
        }
    }
    
    • 设置计算属性
    extension BinaryLeef {
        var values: [Element] {
            switch self {
            case .leaf:
                return []
            case let .node(e, l, r):
                return l.values + [e] + r.values
            }
        }
    }
    
    let tree: BinaryLeef<Int> = .node(6, l: .leaf, r: .leaf)
     print(tree.values)
    
    • 定义泛型方法
    extension BinaryLeef {
        func map<T>(_ transform: (Element)->T) -> BinaryLeef<T> {
            switch self {
            case .leaf:
                return .leaf
            case let .node(e, l, f):
                return .node(transform(e), l: l.map(transform), r: f.map(transform))
            }
        }
    }
    
     let incremented: BinaryLeef<Int> = tree.map{ $0 + 1 }
     print(incremented)
    
    • Swift标准库常见的应用
    • Optional 用泛型参数抽象它包装的类型
    • Result 有两个泛型参数:分别表示成功和失败这两种结果对应的值的类型。
    • Unsafe[Mutable]Pointer 用泛型参数表示指针指向的对象的类型。
    • Key paths 中使用了泛型表示根类型以及路径的值类型。
    • 各种表示范围的类型,使用了泛型表达范围的上下边界

    泛型和Any

    Any作用相似,但是缺少类型安全性,泛型能带来编译期类型检查以及提高运行时性能等额外的好处

    extension Array {
       func reduce<Result>(_ initial: Result,
       _ combine: (Result, Element) -> Result) -> Result
    }
    
    extension Array {
       func reduce(_ initial: Any, _ combine: (Any, Any) -> Any) -> Any
    }
    

    Any无法得知参数和返回值的关系,不易读

    基于泛型的设计

    • 为URLSession添加一个方法
    struct User: Codable {}
    struct NoDataError: Error {}
    
    extension URLSession {
        func loadUser(callBack: @escaping (Result<User, Error>) -> ()) {
            guard let url = URL(string: "") else { return }
            dataTask(with: url) { data, response, error in
                callBack(Result{
                    if let e = error { throw e }
                    guard let d = data else { throw NoDataError() }
                    return try JSONDecoder().decode(User.self, from: d)
                })
            }.resume()
        }
    }
    
    • 修改方法签名,url,解析
    func load<A>(url: URL, parse: @escaping (Data)throws->A, callBack: @escaping (Result<A, Error>) -> ()) {
            dataTask(with: url) { data, response, error in
                callBack(Result{
                    if let e = error { throw e }
                    guard let d = data else { throw NoDataError() }
                    return try parse(d)
                })
            }
        }
    
    • 通过泛型重构去除类似代码
         URLSession.shared.loadUser {
                print($0)
         }
            
         guard let url = URL(string: "") else { return }
         URLSession.shared.load(url: url, parse: { data in
                 }) {
                print($0)
          }
    
    • 由于URL和解析的parse函数成对出现,所以封装到同一个结构体中
    struct Resource<A> {
        let url: URL
        let parse: (Data) throws -> A
    }
    
    let profile = Resource<User>(url: url) { data in
                try JSONDecoder().decode(User.self, from: data)
        }
    
    • 为了避免写重复的编码方法,添加遍历初始化方法
    extension Resource where A: Codable {
        init(json url: URL) {
            self.url = url
            self.parse = { data in
                try JSONDecoder().decode(A.self, from: data)
            }
        }
    }
    
    let profile2 = Resource<User>(json: url)
    

    最后定义接受resource的load版本

    extension URLSession {
        func load<A>(_ resource: Resource<A>, callBack: @escaping (Result<A, Error>) -> ()) {
            dataTask(with: resource.url) { data, response, error in
                callBack(Result{
                    if let e = error { throw e }
                    guard let d = data else { throw NoDataError() }
                    return try resource.parse(d)
                })
            }
        }
    }
    
    let profile2 = Resource<User>(json: url)
    URLSession.shared.load(profile2) {
                print($0)
    }

    相关文章

      网友评论

        本文标题:【Swift进阶笔记】泛型

        本文链接:https://www.haomeiwen.com/subject/julerrtx.html