Swift 5.0 值得关注的特性:增加 Result<T, E: Error> 枚举类型

栏目: Swift · 发布时间: 6年前

内容简介:在异步获取数据的场景中,常见的回调的数据结构是这样的:表示获取成功的数据,表示获取失败的 error。因为数据可能获取成功,也可能失败。因此回调中的数据和错误都是 optional 类型。 比如 CloudKit 中保存数据的一个函数就是这样:这种形式的缺点是没有体现出两种结果的互斥关系:如果数据成功获取到了,那么 error 一定为空。如果 error 有值,数据一定是获取失败了。Swift 中枚举的能力相比 OC 有着很大的进步,每个枚举值除了可以是常规的基础类型,还可以是一个关联的类型。有了这样的特性

在异步获取数据的场景中,常见的回调的数据结构是这样的:表示获取成功的数据,表示获取失败的 error。因为数据可能获取成功,也可能失败。因此回调中的数据和错误都是 optional 类型。 比如 CloudKit 中保存数据的一个函数就是这样:

func save(_ record: CKRecord, completionHandler: @escaping (CKRecord?, Error?) -> Void)
复制代码

这种形式的缺点是没有体现出两种结果的互斥关系:如果数据成功获取到了,那么 error 一定为空。如果 error 有值,数据一定是获取失败了。

Swift 中枚举的能力相比 OC 有着很大的进步,每个枚举值除了可以是常规的基础类型,还可以是一个关联的类型。有了这样的特性后用枚举来优化返回结果的数据结构显得水到渠成:

enum Result<Success, Failure> where Failure : Error {

    /// A success, storing a `Success` value.
    case success(Success)

    /// A failure, storing a `Failure` value.
    case failure(Failure)
}
复制代码

基本用法

定义异步返回结果是 Int 类型的函数:

func fetchData(_ completionHandler: @escaping (Result<Int, Error>) -> Void) {
    DispatchQueue.global().async {
        let isSuccess = true
        if isSuccess {
            let resultValue = 6
            return completionHandler(.success(resultValue))
        } else {
            let error = NSError(domain: "custom error", code: -1, userInfo: nil)
            return completionHandler(.failure(error))
        }
    }
}
复制代码

返回值的类型通过泛型进行约束, Result 第一个泛型类型表示返回值的类型,第二个类型表示错误的类型。对 Result 赋值和常规的枚举一样:

let valueResult: Result<Int, CustomError> = Result.success(4)

// 因为 swift 中会进行类型推断,编译器在确认返回的是 `Result` 类型后,可以省略枚举类型的声明
let errorResult = .failure(CustomError.inputNotValid)
复制代码

取出 Result 值和获取普通的关联类型枚举是一样的:

fetchData { (result) in
    switch result {
    case .success(let value):
        print(value)
    case .failure(let error)
        print(error.localizedDescription)
    }
}
复制代码

如果你只想要获取其中一项的值,也可以直接用 if case 拆包:

fetchDate { (result) in
    if case .success(let value) = result {
        print(value)
    }
}
复制代码

可以判等

Enum 是一个值类型,是一个值就应该可以判断是否相等。如果 Result 的成功和失败的类型都是 Equatable ,那么 Result 就可以判等,源码如下:

extension Result : Equatable where Success : Equatable, Failure : Equatable { }
复制代码

类似的,如果是成功和失败的类型都是 Hashable ,那么 Result 也是 Hashable

extension Result : Hashable where Success : Hashable, Failure : Hashable { }
复制代码

如果实现了 Hashable ,可以用来当做字典的 key。

辅助的 API

map、mapError

与 Dictionary 类似,Swift 为 Result 提供了几个 map value 和 error 的方法。

let intResult: Result<Int, Error> = Result.success(4)
let stringResult = x.map { (value) -> Result<String, Error> in
    return  .success("map")
}

let originError = NSError(domain: "origin error", code: -1, userInfo: nil)
let errorResult: Result<Int, Error> = .failure(originError)
let newErrorResult = errorResult.mapError { (error) -> Error in
    let newError = NSError(domain: "new error", code: -2, userInfo: nil)
    return newError
}
复制代码

flatMap、flatMapError

map 返回的是具体的结果和错误, flatMap 闭包中返回的是 Result 类型。如果 Result 中包含的是数据,效果和 map 一致,替换数据;如果 Result 中包含的是错误,那么不替换结果。

let intResult: Result<Int, Error> = Result.success(4)

// 替换成功
let flatMapResult = intResult.flatMap { (value) -> Result<String, Error> in
    return  .success("flatMap")
}

// 没有执行替换操作,flatMapIntResult 值还是 intResult
let flatMapIntResult = intResult.flatMap { (value) -> Result<String, Error> in
    return  .failure(NSError(domain: "origin error", code: -1, userInfo: nil))
}
复制代码

get

很多时候只关心 Result 的值,Swift 提供了 get() 函数来便捷的直接获取值,需要注意的是这个函数被标记为 throws ,使用时语句前需要加上 try

let intResult: Result<Int, Error> = Result.success(4)

let value = try? intResult.get()
复制代码

可抛出异常的闭包初始化器

很多时候获取返回值的闭包中可能会发生异常代表获取失败的错误,基于这个场景 Swift 提供了一个可抛出异常的闭包初始化器:

enum CustomError: Error, Equatable {
    case inputNotValid
}

let fetchInt = { () -> Int in
    if true {
        return 4
    } else {
        throw CustomError.inputNotValid
    }
}

let result: Result<Int, Error> = Result { try fetchInt() }
复制代码

需要提醒是通过这种方式声明的 Result 的 error 类型只能是 Error ,不能指定特定的 Error


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Cracking the Coding Interview

Cracking the Coding Interview

Gayle Laakmann McDowell / CareerCup / 2015-7-1 / USD 39.95

Cracking the Coding Interview, 6th Edition is here to help you through this process, teaching you what you need to know and enabling you to perform at your very best. I've coached and interviewed hund......一起来看看 《Cracking the Coding Interview》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具