swift 中的 ??

作者: Inlight先森 | 来源:发表于2017-12-20 11:10 被阅读53次

    引言

    最近有幸参加公司的iOS招聘面试,发现很多3年左右工作经验的工程师对 swift 还停留在想要去了解的阶段,一些是由于公司项目的原因,一些是因为个人原因,但 swift 4.0 都已经出了,还在抱着观望的心态实在不像一个做技术的人应有的态度,所以最近想写一些跟 swift 相关的知识点,既作为自己对知识点的整理和保存,也希望能帮助到一些正在学习 swift 的小伙伴~~~

    概念

    空合运算符,当然这个运算符并不是 swift 首创,早在 C#,Perl,PHP7.0.0 等均有此运算符。

    作用

    这是一个非常有用而且常用的操作符,可以用来快速对 nil 进行条件判空,使代码看起来更加简洁。

    • 使用之前
    // 写法一:可选绑定(Optional Binding)
    var username = ""
    if let name = inputName {
        username = name
    } else {
        username = "Guest"
    }
    
    // 写法二:三目运算符(ternary operator)
    let username = inputName != nil ? inputName! : "Guest"
    
    
    • 使用之后
    let username = inputName ?? "Guest" 
    

    事实上 a ?? b 表示将对可选类型a进行为空判断,如果a包含一个值,就进行解封,否则就返回一个默认值b。
    注意:表达式 a 必须是 Optional 类型。默认值 b 的类型必须要和 a 存储值的类型保持一致。

    定义

    public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
    public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T?) rethrows -> T?
    
    • @autoclosure

    @autoclosure作用就是把一句表达式自动地封装成一个闭包,@autoclosure并不支持带有输入参数的写法,只能使用类似 () -> T 的参数才能使用这个特性。所以写接受 @autoclosure 的方法时还需谨慎,在容易产生误解的时候,还是建议使用完整的闭包。

    了解了 @autoclosure 之后 我们来猜一下 ?? 的实现

    • 实现
    public func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T {
        switch optional {
            case .Some(let value):
                return value
            case .None:
                return defaultValue()
        }
    }
    

    到这里我想除了 ?? 的实现之外,对 Optional 的实现应该也有所了解了

    enum Optional<T> : Reflectable, NilLiteralConvertible {
        case None
        case Some(T)
        init()
        init(_ some: T)
        ...
    }
    

    当 Optional 没有值时,返回的 nil 其实就是 Optional.None,即没有值。除了 None 以外,还有一个 Some,当有值时就是被 Some(T) 包装的真正的值,所以拆包其实就是将Some里面的值取出来。

    可能有些朋友会有疑问为什么这里要使用 @autoclosure,直接将 T 作为参数返回不行吗?这正是 @autoclosure 一个最值得称赞的地方。如果我们直接使用 T,那么意味着 ?? 操作符真正取值之前,我们就必须准备好一个默认值,这个默认值的准备和计算会降低性能。但如果 optional 不是 nil,就完全不需要这个默认值,会直接返回 optional 解包后的值。这种情况下默认值的准备就属于过度开销了。使用 @autoclosure 就是将默认值的计算推迟到 optional 确定为 nil 之后。

    相关文章

      网友评论

        本文标题:swift 中的 ??

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