为什么
if let y: Int? = nil { ... }
if let y: Int? = nil as Int?? { ... }
(因而无效的分配),特别是在自己的
时let y: Int? = nil
与
不同let y: Int? = nil as Int??
(因为let y: Int? = nil
是有效的作业)?
答案 0 :(得分:1)
好的,我会用我糟糕的英语技能回答; - )
让我们从这开头:
if let lvalue:T = rvalue { ... }
首先,编译器尝试使用rvalue
换行,将T?
转换为Optional
。例如:
typealias T = Int
let rvalue:Int? = 1
if let lvalue:T = rvalue { ... } // do nothing because `rvalue` is already `T?`
//---
typealias T = Int??
let rvalue:Int = 1
if let lvalue:T = rvalue { ... } // rvalue will be converted to `T?`, that is `Int???`
//---
typealias T = Int
let rvalue:Int?? = 1
if let lvalue:T = rvalue { ... } // error because `rvalue` could not be converted by wrapping with Optional
然后,运行时通过展开一次来查看转换 rvalue
,无论该值是否为nil
。如果不是nil
则分配并成功。
这是if let lvalue:T = rvalue { ... }
另一方面,
let lvalue:T = rvalue
它相似但不一样。编译器尝试将rvalue
转换为T
,而不是T?
。
typealias T = Int??
let rvalue:Int?? = 1
let lvalue:T = rvalue // Do nothing because `rvalue` is `T`
//---
typealias T = Int??
let rvalue:Int = 1
let lvalue:T = rvalue // rvalue will be converted to `T`, that is `Int??`
然后,运行时可以无条件地将rvalue
分配给lvalue
。
我认为这是不同的。
您希望观察这些编译器的工作原理,您可以使用swiftc -dump-ast
命令。
$ cat test.swift
let i:Int? = 1
if let y:Int? = i { }
$ xcrun swiftc -dump-ast test.swift
(source_file
(top_level_code_decl
(brace_stmt
(pattern_binding_decl
(pattern_typed type='Int?'
(pattern_named type='Int?' 'i')
)
(inject_into_optional implicit type='Int?' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14]
(call_expr implicit type='Int' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14]
(constructor_ref_call_expr implicit type='(_builtinIntegerLiteral: Int2048) -> Int' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14]
(declref_expr implicit type='Int.Type -> (_builtinIntegerLiteral: Int2048) -> Int' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14] decl=Swift.(file).Int.init(_builtinIntegerLiteral:) specialized=no)
(type_expr implicit type='Int.Type' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14] typerepr='<<IMPLICIT>>'))
(tuple_expr implicit type='(_builtinIntegerLiteral: Int2048)' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14] names=_builtinIntegerLiteral
(integer_literal_expr type='Int2048' location=test.swift:1:14 range=[test.swift:1:14 - line:1:14] value=1)))))
)
(var_decl "i" type='Int?' access=internal let storage_kind='stored')
(top_level_code_decl
(brace_stmt
(if_stmt
(pattern_binding_decl
(pattern_typed type='Int?'
(pattern_named type='Int?' 'y')
)
(inject_into_optional implicit type='Int??' location=test.swift:2:17 range=[test.swift:2:17 - line:2:17]
(declref_expr type='Int?' location=test.swift:2:17 range=[test.swift:2:17 - line:2:17] decl=test.(file).i@test.swift:1:5 specialized=no)))
(brace_stmt))))
答案 1 :(得分:1)
考虑可选绑定的用途。它允许您获取一个可选值,并调整是否为nil
,如果它不是nil
,则打开包含的值并将其绑定到变量。所以它是这样的:
if let non_optional_var = optional_expr {
...
} else {
...
}
因此,如果optional_expr
的类型为T?
,则non_optional_var
的类型为T
。 (当我写&#34; non_optional_var&#34;我并不意味着它不是可选的,而是表示它的可选性低于&#34; optional_expr& #34;。因此,如果non_optional_var
的类型为Int?
,则optional_expr
的类型为Int??
。
顺便说一句,可选的绑定语法是用于启用Optional
枚举的语法糖:
switch optional_expr {
case .Some(let non_optional_var):
...
case .None:
...
}