nil文字与变量的可选绑定,在Swift中为nil

时间:2014-10-28 16:12:52

标签: swift syntax variable-assignment conditional-statements optional

在Swift中,为什么

var x: Int? = nil
if let y: Int? = x { ... }

表现与

不同
if let y: Int? = nil { ... }

understanding为什么第一个案例成功的原因表明第二个案例也应该如此,所以我一定不能理解。

后者由于分配无效而没有失败,也没有因为可选链接而失败;否则它看起来和前者一样。为什么后者失败了,它与前者有何不同。究竟在什么时候,以及为什么原因,第二个可选绑定被放弃了?

3 个答案:

答案 0 :(得分:9)

if let y: Int? = nil { ... }

相当于

if let y: Int? = nil as Int?? { ... }

相当于

if let y: Optional<Int> = Optional<Optional<Int>>() { ... }

这会尝试将Optional<Optional<Int>>转换为Optional<Int>,但由于Optional<Optional<Int>>()不包含Optional<Int>值而失败,因此会失败。


Oneliner相当于

var x: Int? = nil
if let y: Int? = x { ... } 

if let y: Int? = nil as Int? { ... } 

增加:

我在What does Swift's optional binding do to the type it's arguments?回答。

if let y: Int? = nil as Int? { ... }

编译为:

if let y:Int? = nil as Int? as Int?? { ... }

在这里,我们应该注意nil as Int? as Int?? 等同于nil as Int??。 前者为Optional(Optional<Int>()),后者为Optional<Optional<Int>>()

考虑到这一点,我想,

  

所以我的第一个例子中的可选绑定(确实)“检查内部”并找到nil,这对于分配给Int是完全有效的吗?但我的第二次检查并找到Optional(nil),它不能分配给Int?

Int??的第一个“检查内部”示例,只找到Optional<Int>()类型的Int?值,该值可以分配给Int?;但是第二个发现 nothing 被分配并失败。

答案 1 :(得分:1)

在初始化时设置的

let declares a constant。使用带有let的{​​{1}}语句中的if,然后将初始化常量绑定到 failable 初始化程序的结果,而不是字面上{{1}或另一个文字。

编译器允许您直接使用Optional<T>,而不是&#39; 4&#39;例如,因为nil在Optional之外具有use / context;但是,nil的这种文字使用绕过了初始化程序,因此没有结果可以绑定。在4或Int(4)的情况下,编译器知道某些内容是错误的并且不会编译。

查看以下示例:

nil

......输出:

nil

更新:解释var xnil: Int? = nil var x4: Int? = Int?(4) var xnone: Int? = Int?() var xdefault: Int? = Int() if let znil: Int? = nil { println("znil:\(znil)") } else { println("znil: did not bind") } if let zn0: Int? = Int?(nilLiteral: ()) { println("zn0:\(zn0)") } if let zn1: Int? = Int?(()) { println("zn1:\(zn1)") } if let zn2: Int? = Int?() { println("zn1:\(zn2)") } if let zn3: Int? = Int?.None { println("zn3:\(zn3)") } if Int?.None == nil { println(".None == nil") } if let zo0: Int? = Int?(4) { println("zo0:\(zo0)") } //nil-test.swift:36:20: error: bound value in a conditional binding must be of Optional type //if let zo1: Int? = 4 { // ^ /* if let zo1: Int? = 4 { println("zo1:\(zo1)") } */ //nil-test.swift:51:20: error: bound value in a conditional binding must be of Optional type //if let zo2: Int? = Int(4) { // ^ /* if let zo2: Int? = Int(4) { println("zo2:\(zo2)") } */ if let zxn0: Int? = xnil { println("zxn0:\(zxn0)") } if let zxn1: Int? = x4 { println("zxn1:\(zxn1)") } if let zxn2: Int? = xnone { println("zxn2:\(zxn2)") } if let zxn3: Int? = xdefault { println("zxn3:\(zxn3)") } znil: did not bind zn0:nil zn1:nil zn1:nil zn3:nil .None == nil zo0:Optional(4) zxn0:nil zxn1:Optional(4) zxn2:nil zxn3:Optional(0) 之间的区别。

见这个例子:

Type

......输出:

Type?

...所以,问问自己:

  • 为什么if let a: Int? = nil { println("a: \(a)") } else { println("a: let fail") } if let b1: Int? = Int?(nilLiteral: ()) { // same as Int?() -- added nilLiteral to be explicit here println("b1: \(b1)") } if let b2: Int? = Int?(44) { println("b2: \(b2); b2!: \(b2!)") } if let c1: Int = Int?(44) { println("c1: \(c1)") } if let c2: Int = Int?(nilLiteral: ()) { // Again, Int?() would suffice println("c2: \(c2)") } else { println("c2: let fail") } /// NOTE: these 'd' examples represents a more idiomatic form var m: Int? = Int?() if let d1 = m { println("d1: \(d1)") } else { println("d1: let fail") } m = Int?(444) if let d2 = m { println("d2: \(d2)") } else { println("d2: let fail") } m = Int?() println("m?: \(m?)") if let whyDoThis: Int? = m { println("whyDoThis?: \(whyDoThis?) -- the `let` is telling you nothing about 'm!'") } 失败,a: let fail b1: nil b2: Optional(44); b2!: 44 c1: 44 c2: let fail d1: let fail d2: 444 m?: nil whyDoThis?: nil -- the `let` is telling you nothing about 'm!'! 绑定成功,即使它包含零值?
  • a在此时明确包含零值时,b1为什么会成功?
  • if let whyDoThis ...的价值告诉您m的哪些内容?

最后,对于这种情况,惯用的Swift伪代码应该如下所示:

whyDoThis?

更新2:好的,让我们来看看类型......

请参阅以下示例:

m!

......输出:

var maybeT: MyType?
// ... maybe set maybeT to a MyType, maybe not
if let reallyHaveT = maybeT {
  // reallyHaveT has a bound value of type MyType
}

我想强调的一点是,当你写var none: Int? = Int?() var one: Int? = Int?(1) println("Int() type: \(_stdlib_getTypeName(Int())), val: \(Int())") println("Int(1) type: \(_stdlib_getTypeName(Int(1))), val: \(Int(1))") println("Int?() type: \(_stdlib_getTypeName(Int?())), val: \(Int?())") println("Int?(1) type: \(_stdlib_getTypeName(Int?(1))), val: \(Int?(1))") println("none type: \(_stdlib_getTypeName(none)), val: \(none)") println("one type: \(_stdlib_getTypeName(one)), val: \(one)") if let x = none { println("`let x = none` x type: \(_stdlib_getTypeName(x))") } else { println("`let x = none` FAIL") } if let x: Int = none { println("`let x: Int = none` x type: \(_stdlib_getTypeName(x))") } else { println("`let x: Int = none` FAIL") } if let x: Int? = none { println("`let x: Int? = none` x type: \(_stdlib_getTypeName(x))") } if let y = one { println("`let y = one` y type: \(_stdlib_getTypeName(y))") } if let y: Int = one { println("`let y: Int = one` y type: \(_stdlib_getTypeName(y))") } if let y: Int? = one { println("`let y: Int? = one` y type: \(_stdlib_getTypeName(y))") } if let z: Int? = nil { println("`let z: Int? = nil` z type: \(_stdlib_getTypeName(z))") } else { println("`let z: Int? = nil` FAIL") } if let z = Int?() { println("`let z = Int?()` z type: \(_stdlib_getTypeName(z))") } else { println("`let z = Int?()` FAIL") } 时,你正在有效地调用Int() type: _TtSi, val: 0 Int(1) type: _TtSi, val: 1 Int?() type: _TtSq, val: nil Int?(1) type: _TtSq, val: Optional(1) none type: _TtSq, val: nil one type: _TtSq, val: Optional(1) `let x = none` FAIL `let x: Int = none` FAIL `let x: Int? = none` x type: _TtSq `let y = one` y type: _TtSi `let y: Int = one` y type: _TtSi `let y: Int? = one` y type: _TtSq `let z: Int? = nil` FAIL `let z = Int?()` FAIL 。在let z = Int?()语句中使用时,这将无法绑定。总是。

答案 2 :(得分:0)

if let用于删除可选项。如果你想查看变量何时使用

if let y: Int = x {
// This occurs if you are able to give a non-nil value to the variable
} else {
// This occurs if the optional x is nil
}

据我所知,你不应该尝试在if let语句中声明一个常量的类型是可选的,因为这样会破坏if let语句的用途。