3

可选链接总是返回一个可选值。

为了反映可以对 nil 值调用可选链接这一事实,可选链接调用的结果始终是可选值,即使您正在查询的属性、方法或下标返回非可选值也是如此。

Swift 编程语言

为什么在操场上的类型不是可选的?

let stringOptEmpty: String? = ""
stringOptEmpty?.isEmpty // is true
stringOptEmpty?.isEmpty.dynamicType // Bool.Type

但是下面的代码是

let isOk = stringOptEmpty?.isEmpty.dynamicType
isOk.dynamicType // Optional<Bool.Type>.Type
4

1 回答 1

4

TLDR;

操场侧边栏/列将动态解析操场中的表达式,无论是分配给变量(可变/不可变)的值还是只是“自由浮动”的非分配值。

您的第一个示例适用dynamicTypevalue,它将解析为该特定值的类型true.dynamicType: Bool.Type)。

另一方面,您的第二个示例适用dynamicType变量(不可变,但我将在此处使用variablevalue不同),该变量必须具有具体类型,因此将解析为可以容纳任何类型的类型包装的值(truefalse)以及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 将在解析该值之前动态解析表达式的(/result) dynamicType。由于我们正在处理可选项,因此该或者只是包装类型的值(在本例中为true),或者该值是特定于类型 .None的。即使操场在侧边栏中显示了例如let a: Int? = nilas的结果,显示nil的值实际上与say不同.None( )nillet b: String = nil

  • 因为let a: Int? = nila实际上Optional<Int.Type>.None是_
  • 而对于let b: String? = nil,的值为bOptional<String.Type>.None

考虑到这一点,dynamicTypenil 的解析很自然将是具体的包装类型(在您的示例中,Bool.Type自然是 的类型true),而值的解析dynamicTypenil包括一般可选和包装类型信息.

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变量的这里是不可变的,但使用变量value不同)isOk是可以同时包含.Noneand的类型,.Some<T>无论变量的实际值是什么,因此dynamicType解析为这种类型;Optional<Bool.Type>.Type.


在括号中包装表达式逃脱了 Swift Playground 的运行时自省?

有趣的是,如果一个表达式在应用之前被包裹在括号中.dynamicType,那么操场侧边栏会将.dynamicType包裹的表达式解析为表达式的类型,就好像它的实际值是未知的一样。例如,(...)in(...).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         */

我们可以进一步注意到,在操场上用括号括起来的任何单独的表达式根本不会解决任何问题(在侧边栏中)。如果将表达式包装在括号中,就好像我们逃避了侧边栏:s 运行时自省(这可以解释为什么dynamicType用括号括起来的表达式将解析,就好像操场不能使用这些表达式的运行时信息一样)

var a = 4 // shows '4'
(a = 2)   // shows nothing; can't expand or get details in sidebar

Tbh,我无法解释为什么会这样,并将其归类为 Swift 游乐场的一个特点。

于 2016-05-28T11:23:27.013 回答