可选链接的dynamicType与分配不同 [英] dynamicType of optional chaining not the same as assignment

查看:86
本文介绍了可选链接的dynamicType与分配不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

要反映可以在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

解决方案

TLDR;

游乐场侧边栏/列将动态解析游乐场中的表达式,无论是分配给变量(变量/不可变变量)的值,还是只是自由浮动"的未分配值.

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

另一方面,您的第二个示例将dynamicType应用于变量(不可变,但是在这里我将使用 variable ),它必须具有具体的类型,因此将解析为可以容纳任何类型的包装值(truefalse)以及nil(此处为nil具体来说,是Optional<Bool.Type>.None),无论该变量实际具有什么值.因此,在第二个示例中,dynamicType将解析为Optional<Bool.Type>.Type.


详细信息

在游乐场侧边栏/列中显示的值通常遵循以下显示规则:

  • 对于 assignment 表达式,边栏中显示的值是已分配的值,例如

    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行)中,我们没有赋值,游乐场会在解析表达式的dynamicType之前动态解析表达式的 value (/result)价值.由于我们正在处理可选内容,因此 value 要么只是包装类型的值(在这种情况下为true),要么是特定于 type 的值. .None.即使操场上显示例如边栏中let a: Int? = nil的结果只是nil,实际上显示的值与.None(nil)相同,例如let b: String = nil

  • 对于let a: Int? = nila 实际上是Optional<Int.Type>.None
  • 对于let b: String? = nilb Optional<String.Type>.None

牢记这一点,很自然,非nil 的已解析dynamicType将是具体的包装类型(在您的示例中,Bool.Type自然是true的类型,而解析后的nil值的dynamicType将包括常规的可选信息和包装的类型信息.

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是可以同时容纳.None.Some<T>的类型,无论变量的实际值是多少,因此dynamicType都可以解析为该类型; Optional<Bool.Type>.Type.


用括号括住表达式可以逃避Swift Playground的运行时自省吗?

有趣的是,如果在应用.dynamicType之前将表达式包装在括号中,则游乐场侧边栏会将包装后的表达式的.dynamicType解析为表达式的 type ,就好像它的实际值一样未知.例如,(...).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         */

我们还可以注意到,操场上用括号括起来的任何孤单表达式都根本无法解析为任何东西(在边栏中).如果将表达式包装在括号中,就好像我们逃避了侧边栏的运行时内省(这将解释为什么包裹在括号中的表达式的dynamicType会像操场上无法使用这些表达式的运行时信息一样解析)

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

Tbh,我无法解释为什么会这样,并将其归类为Swift游乐场的特殊之处.

Optional chaining returns always an optional value.

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

Why the heck does in a playground the type not optional?

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

But the following code is

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

解决方案

TLDR;

The playground sidebar/column will dynamically resolve expressions in the playground, be it values assigned to variables (mutables/immutables) or just "free-floating" non-assigned values.

Your first example applies dynamicType to a value, which will resolve to the type of that specific value (true.dynamicType: Bool.Type).

Your second example, on the other hand, applies dynamicType to a variable (an immutable, but I'll use variable here to differ from value), which must have a concrete type, and hence will resolve to a type that can hold any kind of wrapped values (true or false) as well as nil (here, nil is, specifically, Optional<Bool.Type>.None), no matter what value the variable actually holds. Hence, the dynamicType will resolve to Optional<Bool.Type>.Type in your second example.


Details

The value displayed in the playground sidebar/column generally follows the following display rules:

  • For an assignment expression, the value shown in the sidebar is the value assigned, e.g.

    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'. */
    

  • For an expression that contains no assignment, the value shown in the sidebar is generally the result of the expression, e.g.

    true          // shows 'true'
    1 > 3         // shows 'false'
    let c = 3
    c             // shows '3'
    c.dynamicType // shows 'Int.Type'
    

In your first example (lines 2-3), we have no assignment, and the playground will dynamically resolve the value(/result) of the expression prior to resolving the dynamicType of that value. Since we're dealing with optionals, the value is either simply the value of the wrapped type (in this case, true), or the value is a type specific .None. Even if the playground shows e.g. the result of let a: Int? = nil as just nil in the sidebar, the value shown is in fact not the same .None (nil) as for say let b: String = nil

  • For let a: Int? = nil, the value of a is in fact Optional<Int.Type>.None,
  • whereas for let b: String? = nil, the value of b is Optional<String.Type>.None

With this in mind, it's natural that the resolved dynamicType of a non-nil value will be the concrete wrapped type (in your example, Bool.Type is naturally the type of true), whereas the resolved dynamicType of a nil value will include both the general optional and the wrapped type information.

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

Now, if you assign the values to a variable, naturally the variable must have a concrete type. Since the value we assign at runtime can be either .None or .Some<T>, the type of the variable must be one that can hold values of both these cases, hence, Optional<T.Type> (disregarding of whether the variable holds nil or a non-nil value). This is the case which you've shown in your second example: the dynamicType of the variable (here, immutable, but using variable to differ from value) isOk is the type that can hold both .None and .Some<T>, no matter what the actual value of the variable is, and hence dynamicType resolves to this type; Optional<Bool.Type>.Type.


Wrapping expressions in parantheses escapes the runtime introspection of the Swift Playground?

Interestingly, if an expression is wrapped in parantheses prior to applying .dynamicType, then the playground sidebar resolves .dynamicType of the wrapped expression as the type of the expression, as if its actual value was unknown. E.g., (...) in (...).dynamicType is treated as a variable with a concrete type rather than a runtime-resolved value.

/* .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         */

We can further note that any lone expression wrapped in parantheses in the playground will not resolve to anything at all (in the sidebar). It's as if we escape the sidebar:s runtime introspection if wrapping expressions in parantheses (which would explain why the dynamicType of expressions wrapped in parantheses will resolve as if the playground cannot make use runtime information of these expressions)

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

Tbh, I cannot explain why this is, and will categorize it as a peculiarity of the Swift playground.

这篇关于可选链接的dynamicType与分配不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆