2016-04-24 118 views
4
// Swift 
import UIKit 
let arr = [1, "a", 2.88] 
let last = arr.last 
if last is Int { 
    print("The last is Int.") // The last is Int. 
} else { 
    print("The last is not Int.") 
} 

我无法理解打印结果。
为什么打印“最后是Int”。双数字的类型是Int in Swift

// Swift 
import UIKit 
let arr = [1, "a", -2] 
let last = arr.last 
if last is Double { 
    print("The last is Double.") // The last is Double. 
} else { 
    print("The last is not Double.") 
} 

而这个打印“最后是双”为什么?
有人可以帮助我吗?
比你差异很大。

回答

10

Swift数组只能容纳一种类型。当你宣称:

let arr = [1, "a", 2.88] 

斯威夫特取得[NSObject]arr。您可以通过验证此选项 - 点击arr查看其类型。这仅适用于您导入基金会(您的import UIKit也导入Foundation)。尝试删除import UIKit

然后,将值12.88转化为NSNumber"a"NSString以便它们可以被存储在数组[NSObject]因为Int S,String s和Double s为不NSObjectsNSNumberNSStringNSObject的子类。 Swift为数组选择了限制最多的类型。如果你的阵列是[1, true, 2.88],阵列类型应该是[NSNumber]

关于NSNumber有趣的事情是它是一个包装许多不同类型的对象容器。您可以将Int放入并取出Double。所以,当你使用is进行测试时,它会产生误导。它回应“真实”的含义,“如果你愿意,我可以做到”。


import Foundation 

let n: NSNumber = 3.14 

print(n is Int)  // "true" 
print(n is Double) // "true" 
print(n is Bool)  // "true" 

print(n as! Int)  // "3" 
print(n as! Double) // "3.14" 
print(n as! Bool)  // "true" 

注意:假如你宣布你的arr[Any],那么这会工作如你预期:

let arr:[Any] = [1, "a", 2.88] 
let last = arr.last 
if last is Int { 
    print("The last is Int.") 
} else { 
    print("The last is not Int.") // "The last is not Int." 
} 

但斯威夫特不会创建数组输入Any给你,除非你明确要求(因为坦率地说它是强类型语言的可憎)。如果您发现自己使用[Any],您应该重新考虑您的设计。

的唯一原因,雨燕创造[NSObject]基金会是进口的是调用可可可可触摸 API时,使我们的生活更轻松。如果此类API需要传递NSArray,则可以发送[1, "a", 2.88]而不是[NSNumber(integer: 1), NSString(string: "a"), NSNumber(double: 2.88)]

+0

>然后,将这些值转换为“NSNumber”。但是,当我检查'最后一个'变量的类型是'NSObject?',而不是'NSNumber'。 – pacification

+0

'last'返回数组保存的可选变量。该数组是'[NSObject]'。这个特定的实例包含两个'NSNumber'和一个'NSString',它们是'NSObject'的子类。 – vacawama

+0

似乎编译器从来没有推断过类型是'Any'或'[Any]',因此推断这个数组类型的唯一可能的方法是(如果引用了Foundation)正在使用'NSNumber'转换,然后使用'[AnyObject]'或'[NSObject]'。如果没有'Foundation',编译器会触发一个错误。你仍然可以明确地使用'[Any]'。 – Sulthan

0

的问题是你的arr,如果声明

let arr = [1, "a", 2.88] // arr is [NSObject] 

所以

let arr = [1, "a", 2.88] 
let last = arr.last // last is a NSObject? 
if last is Int { // is Int or is Double will get the same result 
    print("The last is Int.") // because the number of NSNumber is larger than the number of NSString 
} else { 
    print("The last is not Int.") 
} 

如果声明是这样的:

let arr = [1, "a", "b"] 
let last = arr.last 
if last is Int { 
    print("The last is Int.") 
} else { 
    print("The last is not Int.") // Will print because the number of NSString is larger than NSNumber. 
} 
0

您可以[Any]类型声明数组得到理想的效果:

let arr: [Any] = [1, "a", 2.88] 
arr.last is Int // false 
0

当您导入Foundation.framework时,您将继承数字的某种魔术行为:如果您创建的数组文字不能用该数值类型的数组表示,那么会创建一个包含数字的数组盒装在NSNumber。如果你没有导入Foundation(也就是你只依赖Swift标准库),那么你实际上不能在这种情况下声明数组,let arr = [1, "a", 2.88](例如let arr = [1,2]仍然可以工作 - 这将产生一个[Int])但需要说明let arr:[Any] = [1, "a", 2.88] - 在这种情况下,没有装箱到NSNumber发生(NSNumber甚至不可用),原始类型以某种方式保留。

的NSNumber是可以用来包装标量的所有方式(数字)基本类型一个框,你可以使用asis运营商斯威夫特成功治疗任何NSNumber的任何数值类型也可以换的。例如以下成立:

var a = NSNumber(bool: true) 
print("\(a is Bool)") // prints "true" 
print("\(a is Int)") // prints "true" 
print("\(a is Double)") // prints "true" 
print("\(a is Float)") // prints "true" 

它可以找出一种你有时会使用数字型的,但它只是不暴露因故NSNumber但只适用于相应的CoreFoundation类型CFNumber

extension NSNumber { 
    var isBoolean:Bool { 
     return CFNumberGetType(self as CFNumber) == CFNumberType.CharType 
    } 

    var isFloatingPoint:Bool { 
     return CFNumberIsFloatType(self as CFNumber) 
    } 

    var isIntegral:Bool { 
     return CFNumberGetType(self as CFNumber).isIntegral 
    } 
} 

extension CFNumberType { 
    var isIntegral:Bool { 
     let raw = self.rawValue 
     return (raw >= CFNumberType.SInt8Type.rawValue && raw <= CFNumberType.SInt64Type.rawValue) 
       || raw == CFNumberType.NSIntegerType.rawValue 
       || raw == CFNumberType.LongType.rawValue 
       || raw == CFNumberType.LongLongType.rawValue 
    } 
} 

您可以阅读更多关于此主题over here - 有一些注意事项。

还要注意the reference documentation还指出以下几点:

...数量的对象不一定与保存在创建 类型...

相关问题