【问题标题】:Weird optional value usage in swiftswift中奇怪的可选值用法
【发布时间】:2014-07-26 00:52:42
【问题描述】:
    var z1 = false
    var z2 = false
    var z3 = false


    if let y1: Int = nil {
        z1 = true
    }

    if let y2: Int? = nil {
        z2 = true
    }

    var x: Int? = nil
    if let y3: Int? = x {
        z3 = true
    }

    println(z1)   // false
    println(z2)   // ture
    println(z3)   // false

我尝试使用这样的可选值(我知道这很奇怪,我只是对深度的可选值感到好奇)。

结果并不如我所料。 z1 是假的,这正如我所料,但为什么 z2 是真的? 赋值后 y2 为 nil,但是 if 语句认为这个表达式(let y2: Int? = nil)为真,执行下一条语句(z2=true),为什么会这样?

为什么 z2 不为假?

如果 y2 只是声明为一个可选值,可以包含另一个可选值,而可选值可能是 nil,if let 语句只是检测到 unwrap 是否成功,那么,为什么 z3 不正确?

【问题讨论】:

    标签: swift optional


    【解决方案1】:

    因为您缺少“?”在z1

    【讨论】:

    • 比较两个'if'语句,两者不同的是“?”在类型之后,最后一个有一个“?”在 Type 之后,但它们会导致两个不同的值。为什么会这样?是某种语言特长还是 swift 的缺陷?
    【解决方案2】:

    这是因为您可以将可选变量声明为递归可选,如下所示:

    var x: Int?? = 5
    // LLDB: p x.dynamicType returns (Int??)
    

    你可以走得更远:

    var y: Int????????? = 6
    // LLDB: p x.dynamicType returns (Int?????????)
    

    if let 构造的作用是检查您是否可以解包可选值,并且碰巧您可以解包可选可选值,即使它的最终值为nil。可以把它想象成可选值不是nil 本身,而是包装nil 的某个对象。

    要在代码中检查它,您可以执行以下操作:

    var a: Int? = nil;
    // LLDB: p a! returns fatal error: Can't unwrap Optional.None
    
    var b: Int?? = nil;
    // LLDB: p b! returns (Int?) $R2 = nil
    

    所以这就是在您的 z2 条件的情况下发生的情况:if let 构造正在检查它是否可以解开 y2 并且确实如此,因此执行了 if 块。

    【讨论】:

    • 你好 MDJ,我已经更新了测试用例,增加了 y3.正如你上面提到的,y2 是一个可选值,它可能包含另一个可选值,if let 语句只是检查解包成功。但是为什么 y3 if let 声明是错误的? x是可选值,y3是可选值的容器,为什么赋值失败?
    【解决方案3】:

    可选绑定的工作方式是 if 检查 let 声明是否成功。在您的第一条语句中,它不成功,因为您不能将 nil 分配给 Int,但在您的第二条语句中,它成功并进入正文,因为您可以将 nil 分配给 Int Optional。

    【讨论】:

      【解决方案4】:

      我将尝试添加块 cmets 来解释它,以便您查看推断的类型和值。

      var z1 = false  
      var z2 = false  
      var z3 = false  
      
      
      if let y1: Int = nil /* nil : Optional<T>   instantiated to Optional<Int>, value is .None */ 
      {
          z1 = true
      }
      
      if let y2: Int? = nil /* nil : Optional<T>   instantiated to Optional<Optional<Int>>, value is .Some(.None) */ 
      {
          z2 = true
      }
      
      var x: Int? = nil   /* nil : Optional<T>   instantiated to Optional<Int>, value is .None */ 
      if let y3: Int? = x /* x : Optional<Int>   value is .None */ 
      {
          z3 = true
      }
      
      println(z1)   // false
      println(z2)   // ture
      println(z3)   // false
      

      【讨论】:

        【解决方案5】:

        对我来说,z2 是假的,z3 是真的:

        println(z1)   // false
        println(z2)   // false
        println(z3)   // true
        

        回想一下if let A = optB { ... }本质上的意思是,“如果optB不是nil,则将其分配给A并执行以下块”,z3为真的原因是x是@ 987654330@ 而不是nil。您可以通过尝试看到这一点

        var x: Int? = 5
        if let y3: Int? = x {
            println(x) // Optional(5)
            z3 = true
        }
        println(z3)    // true
        

        并将此版本与原始版本进行比较

        var x: Int? = nil
        if let y3: Int? = x? {
            z3 = true
        }
        println(z3)   // false!
        

        在第一种情况下,您可以看到 x 被包装(因此原始版本不是 nil 而是 Optional(nil));在第二个中,您可以看到x 是如何展开以生成nil

        Swift(尤其是在 Xcode Playground 中查看)使其难以看到,因为它显示 nil 的方式(可能是因为它无法展开,它显示 Optional(nil)nilnil) .


        顺便说一句,这方面的变化也可用于探索作业左侧发生的一些细微之处,这是z1z2 案例之间的唯一区别。例如,您可以看到z3 的情况与z2 的情况一样,y3 是可选的

        var x: Int? = 5
        if let y3: Int? = x {
            println(x) // Optional(5)
            println(y3) // Optional(5)
            z3 = true
        }
        println(z3)   // true
        

        y3 的类型中删除 ? 使其类似于 z1 的情况,其中 y1 不是可选的

        var x: Int? = 5
        if let y3: Int = x {
            println(x) // Optional(5)
            println(y3) // 5
            z3 = true
        }
        println(z3)   // true
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多