標籤:
Swift基本類型
Swift的類型是在C和OC的基礎上發展而來的,Int是整型;Double和Float是浮點型;Bool是布爾型;String是字串。類似OC,Swift也提出了三個集合類型:Array、Set、Dictionary;
除了上述比較熟悉的類型,Swift還增加了OC中沒有的類型,比如元組(Tuple);Swift還增加了可選(Optional)類型。
Swift是一個型別安全的語言(甚至以此著稱),可選(Optional)就是一個很好的例子。Swift可以讓你清除地知道值的類型。如果你的代碼期望得到一個String,你卻不小心傳入一個Int,Swift的型別安全機制會在開發階段發現這個問題,避免在runtime出錯。
常量和變數
在OC以及C中,一個實值型別或參考型別資料是常量還是變數由關鍵字const
決定。在Swift中,在沒有const這一說嘍。
let和var
Swift使用let來聲明常量,使用var來聲明變數;
聲明
Swift在聲明一個變數或者常量可以攜帶類型資訊,也可以不攜帶。
P.S:聲明變數/常量時,不指明類型而讓Swift編譯器隱式處理的這種行為被稱為『類型推測』(Type Inference),後文有更詳細介紹。
賦值
本來常量和變數是程式設計語言裡非常基礎的概念,沒啥好講的,但Swift世界裡,有些許不同,在賦值過程中,需要注意:
- 無論是常量還是變數,在定義時都可以沒有右值(即沒有初始化值,譬如
var a: Int
或let b: NSObject
),在其他語言中,系統往往會在這種情況下為它們分配一個預設值,譬如OC會設定預設值0或者nil;但這在Swift的世界裡是不可能的,Swift不會為它們設定任何預設值,無論是在什麼時候;
- 無論是常量還是變數,在第一次使用(訪問)之前必須要保證有與類型匹配的值(譬如,
var a:Int; print("a = \(a)")
是不合法的);
- 和其他語言一樣,常量只能進行一次賦值,變數可以進行任意多次賦值;但無論何時,賦值時右值都必須與其定義時的類型匹配,Swift不會幫你做任何轉換;
第3點意味著:
let aInt: Int = 0; aInt = 5
不合法,常量只能進行一次初始化;
var aObject: NSObject; aObject = nil
不合法,右值nil
與NSObject類型不符;
var aInt: Int; aInt = 0.0
不合法,右值0.0
與Int類型不符;
說明:
- 常量/變數使用之前沒有初始化/賦值在Xcode的編譯錯誤通常是:『Variable variableName used before being initialized』;
- 常量/變數賦值時類型不對的編譯錯誤是:『Cannot assign a value of type WrongType to a value of type CorrectType』;
總之,一定要深刻理解到Swift是一門型別安全的語言,《The Swift Programming Language》是這麼說的:
Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String
, you can not pass it an Int
by mistake.
類型推測(Type Inference)
顯然,『類型推測』在處理參考型別時非常便利,這會使得代碼更簡潔;但是在處理實值型別時可能會有些許麻煩,譬如1.0推斷為float還收double?在這種記憶力不是特別牢靠(不太確認)的情況下最好還是顯式寫出變數/常量的類型吧。
靜態局部變數、靜態全域變數、全域變數
「靜態局部變數」、「靜態全域變數」、「全域變數」這些是C語言裡的概念,在Swift似乎不存在。
可選類型(Options)
正如上文所闡述的,Swift是一門『型別安全』的語言,在對對象賦值時,左實值型別和右實值型別必須匹配,否則無法通過編譯;但在OC中,有非常非常多的機會與nil指標打交道,譬如:
- 某個方法/函數返回nil指標,表示返回的對象不存在;
- 某個方法/函數的某個傳入參數為nil,表示傳入空值;
- 某個strong類型指標賦值nil,表示不再持有原對象;
Swift的建立是基於Objective-C的,何況還得保證與之相容,必然考慮到了這個問題,Swift中能夠賦值nil的類型叫「可選類型」(optional
)。
理解optionals
C和OC中並沒有可選這個概念。在OC的對象世界裡,一個指標要麼對應這一個對象,要麼對應著nil;很多時候我們不知道這個指標到底是null 指標,還是有一個有效對象與之對應,所以我們在OC中經常會寫大量大量的if
語句判斷某個指標是否為空白。而在Swift中,不需要這麼麻煩,因為它是一門型別安全的語言,NSObject類型變數在運行時一定有一個NSObject對象與之對應,不可能是nil值。想想這個就激動,想象一下,以前在OC中調用具有傳回值的方法時經常需要對傳回值進行判斷,因為必須要考慮它可能返回nil啊,譬如:
NSMutableArray *aArray = [NSMutableArray array];NSString *aStr = [self aFuckMethod]; // aFuckMethod的實現代碼不可見,不知道一定會返回一個NSStringif (aStr) { [aArray addObject:aStr];}
如果在Swift中,aFuckMethod的
原型為func aFuckMethod() -> String
,則清晰表明了aFuckMethod方法一定會返回一個非String類型對象,那麼上面一段代碼就可以省掉那個if語句了;對比Swift,確實感覺到了OC是一個門太落後的語言,太羅嗦了!
回過頭來闡述Swift的optional
。簡而言之:
You use optionals
in situations where a value may be absent. An optional says:
* There is a value, and it equals x
or
* There is not value at all
相對於OC,Swift的optionals
對實值型別(譬如整型、結構體)和參考型別(類對象)的處理更具一致性
。在OC中,一個方法要不返回一個對象要不返回nil,後者表示『缺乏一個合法的對象』;然而,這隻對對象起作用;對於結構體、基本的C類型或者枚舉都不起作用,處理這些類型,OC方法一般會返回一個特殊值(譬如NSNotFound)來暗示值缺失,這種方法會假設方法的調用者知道並有意識對特殊值進行判斷。然而,Swift的optionals
可以讓你暗示任意類型的缺失,並不需要一個特殊值。
P.S:稍微體會一下,就會意識到Swift的optional
高明多了。
使用optionals
Optional類型預設值
在OC中,若聲明一個對象(指標)但不賦值,系統會預設將之設定為nil;在Swift中也類似,對於一個optional,若不對其賦值,則預設為nil,這可不是我瞎說,文檔有說明:
If you define an optional variable without providing a default value, the variable is automatically set to nil for you.
P.S:似乎這是Swift唯一為變數/常量設定預設值的時機。
簡而言之,你可以對一個optional變數賦值nil,也可以賦值相應的對象。
在OC中,我們經常需要對一個類類型指標進行判斷,判斷它是否為nil;在Swift中使用optional也不省心,也常常需要寫if語句判斷,只是Swift中提供了更多豐富的處理方式。
強制解析(Foreced Unwrapping)符!
You can use an if
statement to find out whether an optional contains a value by comparing the optional against nil
. You perform this comparison with the ==
or !=
.
當你確定可選包確實含值之後,你可以在可選的名字後面加一個驚嘆號!
來擷取值。這個驚歎號表示『我知道這個可選有值,請使用它』,這被稱為可選值的強制解析
(forced unwrapping),如下:
let strNumber = "42"var convertNumber: Int?convertNumber = strNumber.toInt()if convertNumber != nil { println("轉換後的結果為:\(convertNumber!)")}
值得注意的是,使用!
來擷取一個不存在的可選值會導致runtime error。因此使用!
強制解析前,一定要確定optional
包含一個非nil的值。
總之,一定要記住,驚歎號!
對於optional
而言是『強制解析符』,而不是僅僅是『解析符』,這可不是咬文嚼字,雖然只有兩字之差,但意思差遠了。
可選綁定(Optional Binding)
使用可選綁定(optional binding)來判斷optional
是否包含值,如果包含就把值賦給一個臨時常量或者變數。可選綁定可以用在if
和while
語句中來對可選的值進行判斷並把值賦給一個常量或者變數,如下:
let strNumber = "42"if let actualNumber = strNumber.toInt() { println("轉換後的結果為:\(actualNumber)")}
這段代碼可以理解為:
如果strNumber.toInt()
返回的optional
包含一個Int值,則建立一個叫actualNumber的新常量(actualNumber為Int類型)並將可選包含的值賦給它。
這段『可選綁定』的代碼顯然比前一段『強制解析』的代碼要簡短一些,可是,我總覺得Swift的這一部分設計不好,晦澀難懂。首先,
下意識裡,let actualNumber = strNumber.toInt()
等價兩句代碼:let temp = strNumber.toInt()
和let actualNumber = temp
,得到的actualNumber應該是一個optional啊,怎麼文檔給出的解釋暗示actualNumber是一個Int類型變數呢?Fuck!
Implicitly Unwrapped Optionals
『隱式解析可選』作為右值?
『隱式解析可選』似乎比普通optional更安全,既然這麼好,為什麼不放棄前面的普通optional呢?似乎是不行的,文檔這麼說:
Do not use an implicitly unwrapped optional when there is a possibility of a variable becoming nil
at a later point. Always use a normal optional type if you need to check for a nil
value during the lifetime of a variable.
元組(Tuple)
元組概述
元組(tuples)早已經是很多進階語言(譬如Python)的中重要組成成分了,它用來把多個值組合成一個複合值,而這些值可以是任意類型(無所謂變數還是常量,無所謂實值型別還是參考型別,無所謂optional還是non-optional),並不要求是相同類型。
使用元組
分解元組(Decompose Tuple)
Swift中的元組分解(decompose)和Python中差不多,你可以使用如下文法將一個元組分解成單獨的常量和變數:
let http404Error = (404, "Not Found")// http404Error的類型是(Int, String),值是(404, "Not Found") var (status, statusMessage) = http404Error
在decompose時,如果只需要一部分元組資訊,使用_
來標記要忽略的部分。
Tuple支援下標操作
可以使用下標訪問一個元組中指定的元素,譬如http404Error.0
表示訪問上述元組http404Error的第一個元素(值為404的Int型)。
給Tuple元素命名
使用下標訪問Tuple元素難免不夠完美,畢竟數字太冰冷了;Swift的Tuple還支援給Tuple元素命名,譬如:
let http404Error = (status: 404, message:"Not Found")println("狀態代碼:\(http404Error.status), 資訊:\(http404Error.message)")
理解元組
根據我的理解,Tuple並不算一種類型(事實上Swift中也不存在所謂的Tuple
類型),它更應該看成是Swift所支援的一種語言特性(文法)。Tuple看起來像數組,但顯然不同於數組,數組可是一種資料類型,數組包括大量的功能方法,「元組」是不存在所謂的方法的。也正因為如此,元組的使用情境比較單一,一般用來臨時組織資料(譬如組織函數/方法的傳回值和參數)。
Swift初見