swift - 可选链的动态类型与赋值不同

标签 swift swift2 dynamictype optional-chaining

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

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.

The Swift Programming Language


为什么操场上的类型不是可选的?
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 应用于变量(一个不可变的,但我将在此处使用变量与值不同),该变量必须具有具体类型,因此将解析为可以容纳任何类型的类型包装值( truefalse )以及 nil (这里, nilOptional<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? = nila 实际上是 Optional<Int.Type>.None ,
  • 而对于 let b: String? = nilbOptional<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/

    相关文章:

    ios - 名称文本字段成为强制性的然后 UIAlert 停止工作

    swift - 使用 Xcode 9 在 iOS 11 上发布 Google map API

    ios - swift iOS : How do I make an Instagram link?

    swift2 - 如何在 swift 中将底部边框作为子层添加到标签中?

    c# - c#中动态类型的内存使用

    ios - 在不重新加载标题部分的情况下重新加载 UITableView

    ios - NSPredicate 每个父项一个子项

    ios - 数据未在 View Controller Swift 之间传输

    c# - 我正在尝试将对象转换为动态类型,但转换失败并出现 RunTimeBinder 异常

    java - java中有没有类似于swift的dynamicType的关键字