- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
假设我们有:
let a:Int? = nil
// block not executed - unwapping done, type is inferred
if let unwrapped_a = a {
println(unwrapped_a)
}
// block not executed - unwrapping done, type is specified
if let unwrapped_a:Int = a {
println(unwrapped_a)
}
// block gets executed - unwrapping not done, new local constant + assignment is done instead?
if let not_unwrapped_a:Int? = a {
println(not_unwrapped_a)
}
那么我是否应该假设 Swift 在第一种情况下进行解包,而在第二种情况下进行赋值?
这种语法是不是太接近了,不会造成混淆?我的意思是,是的,编译器会警告您在使用 not_unwrapped_a
时您正在使用可选类型,但仍然如此。
更新:
所以在 Airspeed Velocity 的回答之后我发现了另一个(但实际上是相同的)奇怪的案例:
if let not_unwrapped_a:Int???? = a {
println(not_unwrapped_a)
}
a
将被默默地包裹在 Int?????
中。所以它将是 Int??????
的类型(五)——因为 a
已经是可选的。然后它会被解包一次。
最佳答案
情况 1 和情况 2 是相同的——它们都是将 a
的内容赋值给一个新变量。唯一的区别是您让 Swift 在选项 1 中推断 unwrapped_a
的类型,而您在选项 2 中手动给出类型。您需要执行选项 2 的主要原因是如果源值不明确——例如,如果它是一个可以返回多种类型的重载函数。
案例 3 很有趣。
只要你有一个值,如果它有助于类型匹配和代码编译,Swift 总是愿意默默地将它升级为可选的包装值。 Swift 类型的自动升级是相当罕见的(例如,它不会隐式地将 Int16
升级到 Int32
),但可选值是一个异常(exception)。
这意味着您可以在任何需要可选的地方传递值,而不必费心包装它:
func f(maybe: Int?) { ... }
let i = 1
// you can just pass a straight value:
f(i)
// Swift will turn this into this:
f(Optional(i))
因此,在您的最后一个示例中,您已经告诉 Swift 您希望 not_unwrapped_a
成为一个 Int?
。但它是 let
的一部分,需要 a
在分配给它之前解包。
面对这种情况,Swift 让它工作的唯一方法是将 a
隐式包装在另一个可选中,这就是它所做的。现在它是一个可选的,包含一个包含 nil 的可选。这不是一个 nil 值的可选 - 这是一个包含值的可选(包含 nil 的可选)。解包给你一个包含 nil 的可选。 似乎什么都没发生。但它确实发生了 - 它被第二次包裹,然后解开一次。
如果您使用 swiftc -dump-ast source.swift
编译您的示例代码,您可以看到这一点。您会看到短语 inject_into_optional implicit type='Int??'
。 Int??
是一个包含可选值的可选值。
Optionals 包含 optionals 并不是模糊的边缘情况——它们很容易发生。例如,如果您曾经 for...in 遍历包含可选值的数组,或使用下标从包含可选值的字典中获取值,那么该过程涉及可选值的可选值。
另一种思考方式是,如果您将 if let x = y { }
想成*像一个函数,if_let
,定义如下:
func if_let<T>(optVal: T?, block: T->()) {
if optVal != nil {
block(optVal!)
}
}
现在想象一下,如果您提供一个采用 Int?
的 block
– 也就是说,T
将是一个 Int?
。所以 T?
将是一个 Int??
。当您将常规 Int?
与该 block 一起传递到 if_let
时,Swift 会隐式地将其升级为 Int??
以使其编译.这基本上就是 if let not_unwrapped_a:Int?
发生的事情。
我同意,隐式可选升级有时会令人惊讶(更令人惊讶的是 Swift 会升级返回可选值的函数,即如果一个函数采用 (Int)->Int?
,它将升级 (Int)->Int
以返回一个可选的)。但大概感觉是,在这种情况下,为了方便起见,潜在的困惑是值得的。
* 只是一种
关于ios - if let 在显式指定类型时表现得很奇怪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27569694/
我是一名优秀的程序员,十分优秀!