可选链接总是返回一个可选值。
To reflect the fact that optional chaining can be called on a nil value, the result of an optional chaining call is always an optional value, even if the property, method, or subscript you are querying returns a nonoptional value.
为什么操场上的类型不是可选的?
let stringOptEmpty: String? = ""
stringOptEmpty?.isEmpty // is true
stringOptEmpty?.isEmpty.dynamicType // Bool.Type
但是下面的代码是let isOk = stringOptEmpty?.isEmpty.dynamicType
isOk.dynamicType // Optional<Bool.Type>.Type
最佳答案
TLDR;
操场侧边栏/列将动态解析操场中的表达式,无论是分配给变量(可变/不可变)的值还是“自由 float ”的非分配值。
您的第一个示例将 dynamicType
应用于一个值,该值将解析为该特定值的类型( true.dynamicType
: Bool.Type
)。
另一方面,您的第二个示例将 dynamicType
应用于变量(一个不可变的,但我将在此处使用变量与值不同),该变量必须具有具体类型,因此将解析为可以容纳任何类型的类型包装值( true
或 false
)以及 nil
(这里, nil
是 Optional<Bool.Type>.None
),无论变量实际持有什么值。因此,在您的第二个示例中,dynamicType
将解析为 Optional<Bool.Type>.Type
。
细节
在 Playground 侧边栏/列中显示的值一般遵循以下显示规则:
var a = 4 // shows '4'
a = 2 // shows '2'
let b: () = (a = 3)
/* shows '()': the _value_ assigned to 'b', which is the _result_
of the assignment 'a = 3', to which a _side effect_ is that 'a'
is assigned the value '3'. */
true // shows 'true'
1 > 3 // shows 'false'
let c = 3
c // shows '3'
c.dynamicType // shows 'Int.Type'
在您的第一个示例(第 2-3 行)中,我们没有赋值,并且 Playground 将在解析该值的
dynamicType
之前动态解析该表达式的 value(/result)。由于我们正在处理可选项,因此该值要么只是包装类型的值(在本例中为 true
),要么该值是特定于类型的 .None
。即使操场上显示例如let a: Int? = nil
的结果与侧边栏中的 nil
一样,显示的值实际上与 .None
( nil
) 不一样,比如 let b: String = nil
let a: Int? = nil
,a
的 值 实际上是 Optional<Int.Type>.None
, let b: String? = nil
,b
的 值 是 Optional<String.Type>.None
考虑到这一点,非
dynamicType
值的已解析 nil
很自然将是具体的包装类型(在您的示例中, Bool.Type
自然是 true
的类型),而 dynamicType
值的已解析 nil
将包括一般可选和包装的类型信息。struct Foo {
let bar: Bool = true
}
var foo: Foo? = Foo()
/* .Some<T> case (non-nil) */
foo?.bar // true <-- _expression_ resolves to (results in) the _value_ 'true'
foo?.bar.dynamicType // Bool.Type <-- dynamic type of the _result of expression_
true.dynamicType // Bool.Type <-- compare with this
/* .None case (nil) */
foo = nil
foo?.bar.dynamicType // nil <-- _expression_ resolves to the _value_ 'Optional<Foo.Type>.None'
Optional<Foo.Type>.None.dynamicType
// Optional<Foo.Type>.Type <-- compare with this
现在,如果将值分配给变量,自然变量必须具有具体类型。由于我们在运行时分配的值可以是
.None
或 .Some<T>
,变量的类型必须是可以保存这两种情况的值的类型,因此是 Optional<T.Type>
(不管变量是保存 nil
还是非 nil
值)。这就是您在第二个示例中展示的情况:变量的 dynamicType
(这里是不可变的,但使用变量与值不同) isOk
是可以同时保存 .None
和 .Some<T>
的类型,无论实际值是多少变量是,因此 dynamicType
解析为这种类型; Optional<Bool.Type>.Type
。在括号中包装表达式可以逃避 Swift Playground 的运行时内省(introspection)吗?
有趣的是,如果表达式在应用
.dynamicType
之前被包裹在括号中,那么操场边栏会将包裹表达式的 .dynamicType
解析为表达式的类型,就好像它的实际值未知一样。例如,(...)
中的 (...).dynamicType
被视为具有具体类型的变量,而不是运行时解析的值。/* .Some case (non-nil) */
foo?.bar // true
(foo?.bar).dynamicType /* Optional<Bool>.Type <-- as if (...)
is a _variable_ of unknown value */
/* .None case (nil) */
foo = nil
(foo?.bar).dynamicType /* Optional<Bool>.Type <-- as if (...)
is a _variable_ of unknown value */
我们可以进一步注意到,在操场中用括号包裹的任何单独的表达式都不会解析为任何东西(在侧边栏中)。如果将表达式包装在括号中,就好像我们逃避了 sidebar:s 运行时内省(introspection)(这将解释为什么用括号包装的表达式的
dynamicType
将解析为好像操场无法使用这些表达式的运行时信息一样)var a = 4 // shows '4'
(a = 2) // shows nothing; can't expand or get details in sidebar
Tbh,我无法解释为什么会这样,并将其归类为 Swift 游乐场的一个特性。
关于swift - 可选链的动态类型与赋值不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37497586/