【问题标题】:How to unwrap double optionals?如何解开双选项?
【发布时间】:2015-10-10 01:17:33
【问题描述】:

如何解开返回的字符串:

(可选(可选“蓝色”))

var cityName = String()

if let cityAnno = annotation as MGLAnnotation! {
    cityName = String(stringInterpolationSegment: cityAnno.title!)
}

cityLabelName.text = ("\(cityName), \(county)")

cityLabelName 打印为 (Optional "New York")

【问题讨论】:

    标签: swift


    【解决方案1】:

    给定一个双重可选,例如这种双重包装的String

    let a: String?? = "hello"
    print(a as Any) // "Optional(Optional("hello"))\n"
    

    @Leo, showed 你可以使用两次可选绑定

    if let temp = a, let value = temp {
        print(value) // "hello\n"
    }
    

    或强制解包两次:

    print(value!!)  // don't do this - you're just asking for a crash
    

    您可以使用以下 5 种方法来安全地打开双选项:

    方法一:

    你也可以使用模式匹配

    if case let value?? = a {
        print(value) // "hello\n"
    }
    

    正如@netigger 在their answer 中指出的那样,这也可以写成:

    if case .some(.some(let value)) = a {
        print(value) // "hello\n"
    }
    

    虽然不太简洁,但可能更容易阅读。


    方法二:

    或者,您可以使用 nil 合并运算符 ?? 两次:

    print((a ?? "") ?? "")  // "hello\n"
    

    注意:与此处介绍的其他方法不同,这将始终产生一个值。 ""(空的String)如果有一个选项是nil,则使用。


    方法三:

    或者您可以使用 nil 合并运算符 ??可选绑定

    if let value = a ?? nil {
        print(value)  // "hello\n"
    }
    

    这是如何工作的?

    使用双重包装的可选项,变量持有的值可以是以下三项之一:Optional(Optional("some string"))Optional(nil),如果内部可选项是nil,或者nil,如果外部可选项是nil .所以 ?? nil 解开外部可选。如果外部可选项为nil,则?? 将其替换为默认值nil。如果aOptional(nil),那么?? 将展开外部可选,留下nil。此时,如果内部或外部可选选项为nil,您将拥有String?,即nil。如果里面有String,你会得到Optional("some string")

    最后,可选绑定 (if let) 解包Optional("some string") 以获取"some string"可选绑定 失败,如果其中任何一个选项是nil并跳过该块。


    方法四:

    另外,您可以将flatMap可选绑定一起使用:

    if let value = a.flatMap({ $0 }) {
        print(value)  // "hello\n"
    }
    

    方法五:

    有条件地将值转换为类型。令人惊讶的是,这将删除所有级别的选项:

    let a: String?? = "hello"
    let b: String??????? = "bye"
    
    if let value = a as? String {
        print(value)  // "hello\n"
    }
    
    print(b as Any)  // "Optional(Optional(Optional(Optional(Optional(Optional(Optional("bye")))))))\n"
    
    if let value = b as? String {
        print(value)  // "bye\n"
    }
    

    【讨论】:

    • ?? nil 太棒了!
    • 这是最好的答案,尤其是方法3。
    • @Raginmari,带有双重包装的可选项,变量持有的值可能是以下三项之一:Optional(Optional("some string"))Optional(nil),如果内部可选项是nil,或nil如果外部可选是nil。所以a ?? nil 解开外部可选。如果外部可选是nil,那么??将其替换为默认值 nil。如果aOptional(nil),那么??将打开外部可选离开nil。此时,如果内部或外部可选选项为nil,您将获得nil。如果里面有字符串,你会得到Optional("some string")
    • 最后,可选绑定解开Optional("some string") 以获取"some string",否则如果任一可选绑定是nil,它就会失败。
    • 方法 1 和 3 是我在案例中读到的最好的代码 sn-ps。谢谢你这么棒的帖子!
    【解决方案2】:

    试试

    var a:String?? = "1"
    print((a))
    if let b = a,c = b{
        print(c)
    }
    

    操场截图

    你也可以强制解包,但它不安全

    let d = a!!
    

    【讨论】:

      【解决方案3】:

      我必须说接受的答案非常好,我更喜欢那个答案中的method 1。但是我想使用不同的语法,使其更具可读性:

      if case .some(.some(let value)) = a {
          print(value) // "hello\n"
      }
      

      【讨论】:

        【解决方案4】:

        我在Optional 上创建了一个reduce() 方法,将Optional(Optional(U)) 转换为Optional(U)(就像Scala 中的flatten()):

        extension Optional {
            /// - Returns: Given an Optional(Optional(U)) returns an Optional(U)
            func reduce<U>() -> U? {
                switch self {
                case let unwrapped?:
                    return unwrapped as? U
                default:
                    return .none
                }
            }
        }
        

        使用它:

        字符串示例:

        // By using reduce() you directly got a standard optional you can unwrap in the standard way (see answer of @vacawama above).
        let aString: String? = Optional(Optional("Hello")).reduce()
        
        let unwrapped = aString ?? "Default"
        

        整数示例:

        // By using reduce() you directly got a standard optional you can unwrap in the standard way (see answer of @vacawama above).
        let anInt: Int? = Optional(Optional(5)).reduce()
        
        let unwrapped = anInt ?? 10
        

        当我想调用一个可以抛出异常但在当前上下文中我不想捕获它的方法时,我主要使用它。一个例子是读取钥匙串中的用户属性:

        let username: String = (try? keychain.get("username")).reduce() ?? "unknown"
        

        【讨论】:

          【解决方案5】:

          这是更重要的评论。

          考虑这样的双重可选:

          indirect enum S {
            case value(s: S?)
            case none
          }
          

          而普通的可选是这样的:

          enum S {
            case value(s: S)
            case none
          }
          

          理解为什么在第一个示例中使用indirect 对于所问问题的范围并不重要。没有它就无法编译!在第一个示例中,我只是想证明它的 internal 类型也是 optional 类型

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-08-16
            • 1970-01-01
            • 2021-10-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多