【Swift进阶笔记】泛型
2022-03-02 本文已影响0人
BeethOven
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)
}