Swift type inference and type checking issue

依然范特西╮ 提交于 2019-12-10 17:22:12

问题


I'm not looking for an answer like how to do it correctly but why this happens.

Here is the code:

func isInt(param: AnyObject?) {
    if let value = param as? Int {
        print(value)
    } else {
        print("Not Int")
    }

    if let value = param {
        if value is Int {
            print(value)
        } else {
            print("Not Int")
        }
    }
}

let a:AnyObject? = 1.2
let b:Float? = 1.2
let c:Double? = 1.2

isInt(a)
isInt(b)
isInt(c)

I understand in the first if loop, the param is casted to Int and then print out 1.

But why in second if loop, if value is Int is true and then print out 1.2?


回答1:


In your b case, let value = param bridges value to an NSNumber type. For NSNumber, value is Int will always be true.

For unbridged values:

a is Int // always true, AnyObject bridges to NSNumber here
b is Int // false, cast from Float to Int always fails
c is Int // false, cast from Double to Int always fails

This answer assumes Foundation has been imported. Without Foundation, your assignments will fail.




回答2:


Take a look at https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html, specifically:

Instances of the Swift numeric structure types, such as Int, UInt, Float, Double, and Bool, cannot be represented by the AnyObject type, because AnyObject only represents instances of a class type. However, when bridging to Foundation is enabled, Swift numeric values can be assigned to constants and variables of AnyObject type as bridged instances of the NSNumber class.

We can see this in action in a Playground:

let value = 1.2
value.dynamicType                   //Double.Type
value is Int                        //false
let castValue = value as AnyObject
castValue.dynamicType               //__NSCFNumber.Type (a private framework class, part of the NSNumber class cluster)
//NSNumber is bridged to Int, UInt, Float, Double, and Bool so `is` tests for those types will return `true`
castValue is Int                    //true
castValue is Float                  //true
//NSNumber is not bridged to String so an `is` test will return `false`
castValue is String                 //false



回答3:


well, it seems that it if you do the following:

func isInt(param: AnyObject?) {

    if let value = param {
        if value is Double {
            print("I'm a double")
        }
    if value is Int{
            print("I'm an int")
        }else {
            print("Not Int")
        }
    }
}

it will print "I'm a double" for all three and "I'm an int" for all three as well. It seems that when it goes to the if statement it bridges value to NSNumber, which will be true for any NSNumber type.

However, let's say you do the following:

if let value = param {
        if value is String {
            print("I'm a String")
        } 
        if value is Int{
            print("I'm an int")
        }else {
            print("Not Int")
        }
    }
}

since String is not of type NSNumber, it will skip and go to the if value is Int, which is of type NSNumber and return the value.



来源:https://stackoverflow.com/questions/35047451/swift-type-inference-and-type-checking-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!