Home>

I was investigating cast . I was allowed to ask.

let test2: String = "sample"
print ("type Of test2: \ (type (of: test2))")
let test1: Any = test2 as Any
print ("type Of test1: \ (type (of: test1))")


Here, all the print results will be "String" type.
If upcasting is being done, I think test1 will be any, but why is it still a String type ...?

  • Answer # 1

    In PHP,

    $foo = "5";// $foo is a string
    $foo = (int) $foo;// $foo changes to an integer


    In this way, the variable type changes dynamically, and the entity (instance) also works as if it changes. I think aae_11 probably assumes this behavior.

    Swift cannot do this. Swift casting is not a type conversion function like PHP casting. The statementlet test1: Any = test2 as Anyconvertstest2toAnytype and assigns it totest1It is not.

    First, to change a type in Swift, you need to create a new type entity.int1below performs type conversion by creating a newIntentity based onstring1. I'm not casting. Attempting to cast with int2 will result in an error. Even betweenFloatandDoublecannot be converted by casting.

    let string1 = "5" // string1 becomes String type "5".
    let int1 = Int (aString)! // int1 becomes 5 of Int type.
    let int2 = string1 as Int // error "Cannot convert value of type 'String' to type 'Int' in coercion"

    So what is a Swift typecast? Excerpt of explanation

      

    Type casting is a way to check the type of an instance, or to treat that instance as a different superclass or subclass from somewhere else in its own class hierarchy.

      

    Type casting in Swift is implemented with the is and as operators.These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type.

      

    Excerpt :: Apple Inc. "The Swift Programming Language (Swift 5.1)". Apple Books https://books.apple.com/book/the-swift-programming-language-swift-5-1/id881256329

    Interpretation: Typecasting is a function for examining the type of an entity and treating it as a superclass or subclass in the entity's class hierarchy. Implemented withisandasoperators.

    Swift casts can only be used between superclasses and subclasses. Attempting to convert to a different type will result in an error. Also, there is no type conversion function in the first place.

    The

    Anytype is very special, and any type can be cast to and fromAny.
    The statementlet test1: Any = test2 as Anytreatstest2as aAnytype and usesAnytype Assigning to a certaintest1. The entity does not change at all. The only difference is the type of the variable referencing the entity.

    Swift does an implicit cast, so you only have to specify it explicitly whenAnyis involved, for exampleUserDefaultUse.

    let a = UserDefaults.standard.integer (forKey: "storedIntValue")
    let b = UserDefaults.standard.object (forKey: "storedIntValue") as! Int


    If the stored "storedIntValue" key value is of typeInt,aandbare the same. However, if it is not aInttype,awill have someIntvalue, butbWill crash because it fails to cast.

    Because it is dangerous, useAnyonly when the library requires it, and avoid using it yourself. Because it destroys the benefits offered by the type.

  • Answer # 2

    It's written in the official document

    If you don't understand the official document here, you can normally add a question.
    Rather, comments are not searchable, so questions are buried even though they have been written.

      

    "This type (of :) function can be used to find the dynamic type of a value, especially if the dynamic type is different from the static type. Compile-time value type.The dynamic type of the value is the actual type of the runtime value and may be a subtype of the concrete type. "
    First of all, there is an explanation of the static type of the value, "It is a known compile-time value type." I don't know what this means. And as an explanation of dynamic types, there is "subtype of concrete type", but I don't know what it means


    About static types (known compile-time types)

      

    "Known compile-time value types."

    A type defined in the source code.
    The dynamic type is the actual type at runtime.

    func printInfo (_ value: Any) {
        let t = type (of: value)
        print ("'\ (value)' of type '\ (t)'")
    }
    let count: Int = 5
    printInfo (count)
    // '5' of type 'Int'

    count is the static type Int.
    The dynamic type is 5, so it is Int.

    I'm passing this count variable to the printInfo function

    The static type of the dummy argument value in the printInfo function is Any.
    And the dynamic type obtained with type (of :) is Int.

    In the questioner's code

    let test2: String = "sample"
    print ("type Of test2: \ (type (of: test2))")
    let test1: Any = test2 as Any
    print ("type Of test1: \ (type (of: test1))")


    The String of test2 and the Any part of test1 are static types.

      

    "Subtypes of concrete types"

    In short, it ’s a downcast.
    The function argument is generic, so it's not possible to use Any, but I think the parent type is often defined (static type).
    It means getting an inherited type (subtype) that is an actual instance, not the original type.

    Back to the original question

      

    I think test1 will be any

    The idea of ​​becoming an Any is misunderstood, and it is correct to get the original type String.

    Static? dynamic? It might be confusing, but in a simple example.
    Because we defined "String" in the source, it does n’t mean the actual situation is String.
    In the following, the character "String" does not appear, but since the actual condition of "sample" is String, the result of type (of :) is String.

    let test1: Any = "sample"
    print ("type Of test1: \ (type (of: test1))")

  • Answer # 3

    Do you know that the type recognized by the compiler only changes?


    Additional
    (Note: The word label used in the explanation below is used for explanation, not a term commonly used in Swift)

    The compiler labels each variable/constant with a type label at compile time.
    The compiler uses the labels to determine the methods and properties that can be used.

    let a = 0
    let b = a as Any


    , B as an entity remains Int, but the type as a label recognized by the compiler is Any.
    So if you try to use Int methods and properties for b, it will result in a compile error.

    However, type (of :) looks at the entity, not the label, so it returns the Metatype of the entity.

  • Answer # 4

    First, the type of the variable (or constant) and the type of the value contained in the variable may not always match.
    For example, iflet a: Any = "text", the type ofais Any, but the actual value type isstring

    With

    , an upcast only allows the cast target to be used as a superclass, not something that rewrites the value itself.
    So
    let test1: Any = test2 as Any
    Is
    let test1: Any = test2
    It is the same as writing.

    Next about type (),
    The type of the variable itself can be found by looking at the source code (= static), so there is no need to examine it, for example,stringtype variablesvariabletype isstring.
    The type of the value contained in the variable is not always determined by looking at the source code. Determined at runtime. (= Dynamic)
    The type () function checks the dynamic type.


    Bonus: Casting reference

    type-casting-operator

      

      Theasoperator performs a cast when it is known at compile time that the cast always succeeds, such as upcasting or bridging. variable. The following approaches are equivalent:

    func f (_ any: Any) {print ("Function for Any")}
        func f (_ int: Int) {print ("Function for Int")}
        let x = 10
        f (x)
        // Prints "Function for Int"
        let y: Any = x
        f (y)
        // Prints "Function for Any"
        f (x as Any)
        // Prints "Function for Any"

    Theasoperator is used for casts that are known to succeed at compile time (eg upcast)

    Expression can be used as a supertype without intermediate variables (using upcast)