In Swift, why does
在斯威夫特,为什么
var x: Int? = nil
if let y: Int? = x { ... }
behave differently from
行为不同于
if let y: Int? = nil { ... }
My understanding of why the first case succeeds suggests that the second should as well, so I must not really be understanding.
我对第一个案例成功的理解表明,第二个案例也应该如此,所以我不能真正理解。
The latter is not failing because of an invalid assignment, nor because of optional chaining; and otherwise it seems the same as the former. Why does the latter fail, and how is it different from the former. Exactly at what point, and for what reason, is the second optional binding abandoned?
后者并不是由于分配无效而失败,也不是因为可选的链接;否则它看起来和前者一样。为什么后者会失败,它与前者有何不同?确切地说,在什么时候,以及出于什么原因,第二个可选绑定被放弃了?
3 个解决方案
#1
9
if let y: Int? = nil { ... }
is equivalent to
相当于
if let y: Int? = nil as Int?? { ... }
is equivalent to
相当于
if let y: Optional<Int> = Optional<Optional<Int>>() { ... }
This tries to cast Optional<Optional<Int>>
to Optional<Int>
, and it fails because Optional<Optional<Int>>()
does not contains Optional<Int>
value.
它尝试将可选的 <可选
Oneliner equivalent to
Oneliner相当于
var x: Int? = nil
if let y: Int? = x { ... }
is
是
if let y: Int? = nil as Int? { ... }
ADDED:
补充道:
As I answered on What does Swift's optional binding do to the type it's arguments?.
正如我所回答的,Swift的可选绑定对类型的参数有什么影响?
if let y: Int? = nil as Int? { ... }
is compiled as:
编译:
if let y:Int? = nil as Int? as Int?? { ... }
Here, we should mind that nil as Int? as Int??
is not equivalent to nil as Int??
. The former is Optional(Optional<Int>())
, but the latter is Optional<Optional<Int>>()
.
这里,我们应该把nil看成Int?作为Int ? ?不等于nil作为Int??前者是可选的(可选的
With this in mind, I think,
考虑到这一点,我认为,
So the optional binding in my first example (does indeed) "check inside" and finds nil, which is perfectly valid to assign to Int?; but my second checks and finds Optional(nil), which can't be assigned to Int?
第一个例子中的可选绑定(确实)“检查内部”并找到nil,这完全有效地分配给Int?但是我的第二个检查和查找可选(nil),它不能被分配给Int?
The first example "check inside" of Int??
and just finds Optional<Int>()
value that is Int?
type which can be assigned to Int?
; But the second one finds nothing to be assigned and fails.
第一个例子“检查内部”的Int??然后找到可选的
#2
1
let
declares a constant that is set at initialization time. Using the let
in an if
statement with an Optional<T>
, then it binds the initialized constant the the result of a failable initializer, not literally to nil
or another literal.
声明一个在初始化时间设置的常量。使用if语句中的let(如果带有可选的
The compiler allowed you to use nil
directly, instead of '4' for e.g., since nil
has use/context outside of Optional; however, this literal use of nil
bypasses the initializer, so there is no result to bind to. In the cases of 4 or Int(4), the compiler knows something is awry and won't compile.
编译器允许您直接使用nil,而不是“4”,因为nil在可选的范围之外使用/上下文;但是,这个文本使用nil绕过了初始化器,所以没有结果绑定到。在4或Int(4)的情况下,编译器知道有些错误,无法编译。
Review the following example:
检查下面的例子:
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)")
}
... it outputs:
…输出:
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)
UPDATE: Explaining the difference between Type
and Type?
.
更新:解释类型和类型的区别?
See this example:
看这个例子:
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!'")
}
... it outputs:
…输出:
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!'!
... so, ask yourself:
…所以,问问自己:
- Why did
a
fail, andb1
bind successfully, even though it contains a nil value? - 为什么失败了,b1绑定成功了,即使它包含一个nil值?
- Why does
if let whyDoThis ...
succeed whenm
clearly contains a nil value at that point? - 如果让whyDoThis…当m清楚地包含一个空值时是否成功?
- And what does the value of
whyDoThis?
tell you aboutm!
? - whyDoThis的价值是什么?告诉你关于m ! ?
In the end, idiomatic Swift pseudocode, for this case, should look like the following:
最后,idiomatic Swift伪代码,对于这种情况,应该如下所示:
var maybeT: MyType?
// ... maybe set maybeT to a MyType, maybe not
if let reallyHaveT = maybeT {
// reallyHaveT has a bound value of type MyType
}
UPDATE 2: Okay, let's look at types ...
更新2:好的,让我们看看类型…
See the following example:
看下面的例子:
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")
}
... it outputs:
…输出:
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
The point I want to stress is that you are effectively invoking let z = Int?()
when you write let z: Int? = nil
. This will fail to bind when used in an if
statement. Always.
我想强调的一点是,当您写入let z: Int时,您实际上是在调用let z = Int?()=零。在if语句中使用时,这将无法绑定。总是这样。
#3
0
if let
is used to get rid of the optional. If you want to see when the variable is nil use
如果让它被用来除去可选的。如果你想知道变量何时为nil。
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
}
as far as I know you shouldn't try declare the type of a constant in the if let
statement to be optional because that kind of defeats the purpose of the if let statement.
据我所知,你不应该在if let语句中声明一个常量的类型,因为这样会违背if let语句的目的。
#1
9
if let y: Int? = nil { ... }
is equivalent to
相当于
if let y: Int? = nil as Int?? { ... }
is equivalent to
相当于
if let y: Optional<Int> = Optional<Optional<Int>>() { ... }
This tries to cast Optional<Optional<Int>>
to Optional<Int>
, and it fails because Optional<Optional<Int>>()
does not contains Optional<Int>
value.
它尝试将可选的 <可选
Oneliner equivalent to
Oneliner相当于
var x: Int? = nil
if let y: Int? = x { ... }
is
是
if let y: Int? = nil as Int? { ... }
ADDED:
补充道:
As I answered on What does Swift's optional binding do to the type it's arguments?.
正如我所回答的,Swift的可选绑定对类型的参数有什么影响?
if let y: Int? = nil as Int? { ... }
is compiled as:
编译:
if let y:Int? = nil as Int? as Int?? { ... }
Here, we should mind that nil as Int? as Int??
is not equivalent to nil as Int??
. The former is Optional(Optional<Int>())
, but the latter is Optional<Optional<Int>>()
.
这里,我们应该把nil看成Int?作为Int ? ?不等于nil作为Int??前者是可选的(可选的
With this in mind, I think,
考虑到这一点,我认为,
So the optional binding in my first example (does indeed) "check inside" and finds nil, which is perfectly valid to assign to Int?; but my second checks and finds Optional(nil), which can't be assigned to Int?
第一个例子中的可选绑定(确实)“检查内部”并找到nil,这完全有效地分配给Int?但是我的第二个检查和查找可选(nil),它不能被分配给Int?
The first example "check inside" of Int??
and just finds Optional<Int>()
value that is Int?
type which can be assigned to Int?
; But the second one finds nothing to be assigned and fails.
第一个例子“检查内部”的Int??然后找到可选的
#2
1
let
declares a constant that is set at initialization time. Using the let
in an if
statement with an Optional<T>
, then it binds the initialized constant the the result of a failable initializer, not literally to nil
or another literal.
声明一个在初始化时间设置的常量。使用if语句中的let(如果带有可选的
The compiler allowed you to use nil
directly, instead of '4' for e.g., since nil
has use/context outside of Optional; however, this literal use of nil
bypasses the initializer, so there is no result to bind to. In the cases of 4 or Int(4), the compiler knows something is awry and won't compile.
编译器允许您直接使用nil,而不是“4”,因为nil在可选的范围之外使用/上下文;但是,这个文本使用nil绕过了初始化器,所以没有结果绑定到。在4或Int(4)的情况下,编译器知道有些错误,无法编译。
Review the following example:
检查下面的例子:
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)")
}
... it outputs:
…输出:
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)
UPDATE: Explaining the difference between Type
and Type?
.
更新:解释类型和类型的区别?
See this example:
看这个例子:
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!'")
}
... it outputs:
…输出:
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!'!
... so, ask yourself:
…所以,问问自己:
- Why did
a
fail, andb1
bind successfully, even though it contains a nil value? - 为什么失败了,b1绑定成功了,即使它包含一个nil值?
- Why does
if let whyDoThis ...
succeed whenm
clearly contains a nil value at that point? - 如果让whyDoThis…当m清楚地包含一个空值时是否成功?
- And what does the value of
whyDoThis?
tell you aboutm!
? - whyDoThis的价值是什么?告诉你关于m ! ?
In the end, idiomatic Swift pseudocode, for this case, should look like the following:
最后,idiomatic Swift伪代码,对于这种情况,应该如下所示:
var maybeT: MyType?
// ... maybe set maybeT to a MyType, maybe not
if let reallyHaveT = maybeT {
// reallyHaveT has a bound value of type MyType
}
UPDATE 2: Okay, let's look at types ...
更新2:好的,让我们看看类型…
See the following example:
看下面的例子:
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")
}
... it outputs:
…输出:
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
The point I want to stress is that you are effectively invoking let z = Int?()
when you write let z: Int? = nil
. This will fail to bind when used in an if
statement. Always.
我想强调的一点是,当您写入let z: Int时,您实际上是在调用let z = Int?()=零。在if语句中使用时,这将无法绑定。总是这样。
#3
0
if let
is used to get rid of the optional. If you want to see when the variable is nil use
如果让它被用来除去可选的。如果你想知道变量何时为nil。
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
}
as far as I know you shouldn't try declare the type of a constant in the if let
statement to be optional because that kind of defeats the purpose of the if let statement.
据我所知,你不应该在if let语句中声明一个常量的类型,因为这样会违背if let语句的目的。