2016-04-24 117 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還指出以下幾點:

...數量的對象不一定與保存在創建 類型...

相關問題