類型
在Swift中匿值,有兩種類型:命名型類型和復(fù)合型類型。命名型類型是在定義時可以給定的特定名字的類型赂摆。命名型類型包括類挟憔,結(jié)構(gòu)體钟些,枚舉和協(xié)議。例如绊谭,自定義的類MyClass
的實例擁有類型MyClass
政恍。除了自定義類型之外,Swift標(biāo)準(zhǔn)庫定義了許多常用的命名型類型达传,包括那些表示數(shù)組篙耗、字典和可選值的類型。
那些通常被其它語言認(rèn)為是基本或初級的數(shù)據(jù)型類型-例如表示數(shù)字宪赶、字符和字符串的類型-實際上就是命名型類型宗弯,在Swift標(biāo)準(zhǔn)庫中用結(jié)構(gòu)體來定義和實現(xiàn)。因為它們是命名型類型搂妻,你可以通過使用擴展增加它們的行為來符合你程序的需求蒙保,按 Extensions 和 Extensin Declaration 里討論的那樣。
復(fù)合型類型是沒有名字的類型欲主,定義在Swift語言本身中邓厕。有兩種復(fù)合型類型:函數(shù)型類型和元組型類型。一個復(fù)合型類型可以包含命名型類型和其他復(fù)合型類型扁瓢。例如邑狸,元組型類型(Int,(Int,Int))
包含兩個元素:第一個是命名型類型Int,第二個是另一個復(fù)合型類型(Int,Int)
本節(jié)討論Swift語言本身定義的類型并描述Swift中的類型推斷行為涤妒。
GRAMMAR OF A TYPEtype → array-type- | dictionary-type- | function-type- | type-identifier- | tuple-type- | optional-type- | implicitly-unwrapped-optional-type- | protocol-composition-type- | metatype-type-
類型注釋
類型注釋顯示的指定一個變量或表達(dá)式的類型单雾。類型注釋以冒號(:
)開始以類型結(jié)束。let someTuple: (Double, Double) = (3.14159, 2.71828)func someFunction(a: Int){ /* ... / }
在第一個例子中她紫,表達(dá)式someTuple
+的類型被指定為元組類型(Double, Double)
硅堆。在第二個例子中,函數(shù)someFunction
的參數(shù)a的類型被顯示指定為類型Int
贿讹。
類型注釋可以包含一個可選的類型特性的列表在類型之前渐逃。
GRAMMAR OF A TYPE ANNOTATIONtype-annotation* → :- attributes- opt inout -opt -type-
類型標(biāo)識符
類型標(biāo)識符指的是命名型類型或者是命名型或復(fù)合型類型的別名。
大多數(shù)情況下民褂,類型標(biāo)識符指的是與類型標(biāo)識符同名的命名型類型茄菊。例如Int類型標(biāo)識符指的是命名型類型Int
,類型標(biāo)識符Dictionary<String, Int>
指的是命名型類型Dictionary<String, Int>
赊堪。
有兩種情況類型標(biāo)識符不是指的是和類型標(biāo)識符同名的類型面殖。情況一,類型標(biāo)識指的是某個命名型或復(fù)合型類型的類型別名哭廉。例如脊僚,在下面的例子中,類型注釋中Point
的用法指的是元組類型(Int, Int)
:typealias Point = (Int, Int)let origin: Point = (0, 0)
情況二遵绰,類型標(biāo)識符使用dot( . )語法來表示聲明在其它模塊中或嵌套在其它類型中的命名型類型辽幌。例如增淹,下面代碼中的類型標(biāo)識符指的是在ExampleModule
模塊中聲明的命名型類型MyType
:var someValue: ExampleModule.MyType
GRAMMAR OF A TYPE IDENTIFIERtype-identifier → type-name-generic-argument-clause -opt | type-name-generic-argument-clause- opt -.-type-identifier-type-name → identifier-
元組類型
元組類型是是使用逗號分隔的0個或多個類型的列表,用括號括起來乌企。你可以使用元組類型作為函數(shù)的返回值使函數(shù)返回一個包含多個值的元組虑润。你也能命名元組的元素并且使用那些名字來表示每個元素的值。一個元素的名字由一個標(biāo)識符與緊隨其后的冒號(:)組成加酵。例如在函數(shù)和多返回值中所展現(xiàn)的這些特點拳喻。參閱 Functions with Multiple Return Values.
Void
是空元組類型()
的別名。如果括號中只有一個元素虽画,類型就是那個元素的類型。例如荣病,類型(Int)就是Int码撰,不是(Int)。因此个盆,你可以命名一個元組中的元素當(dāng)元組有2個或多個元組時脖岛。
GRAMMAR OF A TUPLE TYPEtuple-type → (-tuple-type-body -opt-)-tuple-type-body → tuple-type-element-list-... -opttuple-type-element-list → tuple-type-element -| tuple-type-element-,-tuple-type-element-list- tuple-type-element → attributes- opt -inout -opt -type- | element-name-type-annotation-element-name → identifier
函數(shù)類型
函數(shù)類型表示一個函數(shù)、方法或閉包的類型颊亮,由參數(shù)類型和返回值類型組成柴梆,中間用箭頭(->
)隔開:(parameter type) -> (return type)
因為參數(shù)類型和返回值類型可以是元組類型,函數(shù)類型支持多參數(shù)與多返回值的函數(shù)與方法终惑。
函數(shù)類型的參數(shù)() - > T
(其中T是任何類型)可以應(yīng)用autoclosure屬性明確創(chuàng)建閉包在其調(diào)用點绍在。這提供了語法上的方便的方式來推遲表達(dá)式的賦值,而不需要在調(diào)用函數(shù)寫一個明確的閉包雹有。例如自動閉包函數(shù)類型參數(shù)偿渡,參見Autoclosures。
函數(shù)類型可以有可變參數(shù)在它的參數(shù)類型中霸奕。在語法上溜宽,一個可變參數(shù)由一個緊跟三個點(...)的基本類型名組成,如Int... .
一個可變參數(shù)被視為包含基本類型元素的數(shù)組质帅。例如适揉,一個可變參數(shù)Int...被視為[Int]。使用可變參數(shù)的示例煤惩,請參閱可變參數(shù)嫉嘀。為了指定輸入輸出參數(shù),把inout關(guān)鍵字綴于在參數(shù)類型之前魄揉。你不能用inout關(guān)鍵字標(biāo)記可變參數(shù)或返回值類型吃沪。輸入輸出參數(shù)參閱 In-Out Parameters。
如果函數(shù)類型包括不止一個箭頭(->)什猖,函數(shù)類型從右到左進(jìn)行分組票彪。例如红淡,函數(shù)類型(Int) -> (Int) -> (Int)
被理解為(Int) -> ((Int) -> (Int))
——也就是說,一個函數(shù)的參數(shù)為Int 類型降铸,其返回類型是一個參數(shù)類型為Int返回類型為Int 的函數(shù)類型
函數(shù)類型如果能拋出錯誤必須使用throws
關(guān)鍵字來標(biāo)記在旱,而且函數(shù)類型如果能重拋錯誤則必須使用rethrows
關(guān)鍵字來標(biāo)記。throws
關(guān)鍵字是函數(shù)類型的一部分推掸,不拋出函數(shù)是拋出函數(shù)的子類型桶蝎。所以,你可以使用不拋出函數(shù)或拋出函數(shù)在同樣的位置谅畅。拋出和重拋函數(shù)的參考 拋出函數(shù)與方法和重拋函數(shù)與方法登渣。拋出和沖拋出函數(shù)在 Throwing Functions and Methods和Rethrowing Functions and Methods中有描述。
GRAMMAR OF A FUNCTION TYPEfunction-type → (-type-)- ** throws- opt -->- type-function-type → (-type-)- rethrows-->-type
數(shù)組類型
Swift語言為Swift標(biāo)準(zhǔn)庫中Array<Element>類型提供下列語法糖:[ type ]
換句話說毡泻,下面兩個聲明是等價的:let someArray: [String] = ["Alex", "Brian", "Dave"]let someArray: Array<String> = ["Alex", "Brian", "Dave"]
上面兩種情況中胜茧,常量someArray
被聲明為字符串?dāng)?shù)組。數(shù)組的元素可以被訪問通過下標(biāo)在方括號中指定一個有效的索引值: someArray[0] 是指第0個元素"Alex"
仇味。
你可以創(chuàng)建多維數(shù)組通過嵌套多對方括號呻顽,元素的基本類型名包含在最里面的方括號。例如丹墨,下面例子中用三對方括號創(chuàng)建三維整數(shù)數(shù)組廊遍。var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
訪問一個多維數(shù)組的元素時,最左邊的下標(biāo)索引值指的是最外層數(shù)組的相應(yīng)位置元素贩挣。接下來的下標(biāo)索引值指的是第一層嵌套的的相應(yīng)位置元素喉前。依次類推。這意味著在上面的例子中王财,array3D[0]
指的是[[1, 2], [3, 4]]
被饿,array3D[0][1]
是指[3, 4]
,array3D[0][1][1]
則是指值4
搪搏。
關(guān)于Swift標(biāo)準(zhǔn)庫中Array
類型的詳細(xì)討論狭握,參閱Arrays。
GRAMMAR OF AN ARRAY TYPEarray-type → [-type-]
字典類型
Swift語言為Swift標(biāo)準(zhǔn)庫中的Dictionary<Key,Value>
類型提供下列語法糖:[ key type: value type ]
換句話說疯溺,下面兩個聲明是等價的:
let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
上面兩種情況中论颅,常量someDictionary
被聲明為鍵為String類型,值為Int類型的字典
字典中的值可以通過下標(biāo)指定方括號中的相應(yīng)鍵來訪問:someDictionary["Alex"]
指的是和鍵Alex
關(guān)聯(lián)的值囱嫩。下標(biāo)返回一個字典中鍵的類型的可選恃疯。如果被指定的鍵在字典中不存在的話,下標(biāo)返回nil
墨闲。
字典中鍵的類型必須遵守Swift標(biāo)準(zhǔn)庫中的Hashable
協(xié)議今妄。
關(guān)于Swift標(biāo)準(zhǔn)庫中Dictionary
類型的詳細(xì)討論可,參閱Dictionaries。
GRAMMAR OF A DICTIONARY TYPEdictionary-type → [-type-:-type-]-
可選類型
Swift為命名類型Optional<Wrapped>
定義后綴?
作為語法糖 盾鳞,其定義在Swift標(biāo)準(zhǔn)庫中犬性。換句話說,下列兩種聲明是等價的:var optionalInteger: Int?var optionalInteger: Optional<Int>
在上述兩種情況下腾仅,變量optionalInteger
都被聲明為可選整型類型乒裆。注意在類型和?
之間沒有空格。
類型Optional<Wrapped>
是有兩種情況的枚舉推励,none
和Some(Wrapped)
鹤耍,其代表可能沒有值或可能有值。任意類型都可以被顯式的聲明(或隱式的轉(zhuǎn)換)為可選類型验辞。如果你在聲明可選的變量或?qū)傩詴r沒有提供初始值稿黄,它的值則會自動賦值nil 。
如果一個可選類型的實例包含一個值跌造,那么你就可以使用后綴操作符!
來獲取該值杆怕,如下描述:optionalInteger = 42optionalInteger! // 42
使用!
操作符獲解析一個值為nil的可選會導(dǎo)致運行時錯誤。
你也可以使用可選鏈和可選綁定來有條件的的執(zhí)行對可選表達(dá)式的操作鼻听。如果值為nil
财著,不會執(zhí)行任何操作并且因此沒有產(chǎn)生運行時錯誤联四。
關(guān)于更多的信息以及查看如何使用可選類型的栗子撑碴,參閱Optionals。
GRAMMAR OF AN OPTIONAL TYPEoptional-type → type-?-
隱式解析可選類型
Swift為命名類型Optional<Wrapped>
定義后綴!
作為語法糖 朝墩,其定義在Swift標(biāo)準(zhǔn)庫中醉拓,以及當(dāng)它被訪問時它自動解析的附加行為。如果你試圖使用一個值為nil
的隱式解析收苏,你會得到一個運行時錯誤亿卤。除了隱式解析的行為之外,下面兩個聲明是等價的:var implicitlyUnwrappedString: String!var explicitlyUnwrappedString: Optional<String>
注意類型與!
之間沒有空格鹿霸。
因為隱式解析可選改變了包含該類型的聲明的含義排吴,嵌套在元組類型或泛型類型中的可選類型-如字典或數(shù)組中元素的類型-不能被標(biāo)記為隱式解析。例如:let tupleOfImplicitlyUnwrappedElements: (Int!, Int!) // Errorlet implicitlyUnwrappedTuple: (Int, Int)! // OK
let arrayOfImplicitlyUnwrappedElements: [Int!] // Errorlet implicitlyUnwrappedArray: [Int]! // OK
因為隱式解析可選有相同的Optional<Wrapped>
類型作為可選值懦鼠,你可以使用隱式解析可選在代碼中所有你使用可選的相同地方钻哩。例如,你可以把隱式解析可選賦值給變量,常量肛冶,以及可選屬性街氢,反之亦然。
有了可選睦袖,在聲明隱式解析可選的變量或?qū)傩詴r你不用提供初始值珊肃,它的值會自動賦值為nil
。
使用可選鏈有條件的對隱式解析可選的表達(dá)式進(jìn)行操作。如果值為nil
伦乔,就不執(zhí)行任何操作厉亏,因此也不會產(chǎn)生運行錯誤。
關(guān)于隱式解析可選的更多信息评矩,參閱Implicitly Unwrapped Optionals叶堆。
GRAMMAR OF AN IMPLICITLY UNWRAPPED OPTIONAL TYPEimplicitly-unwrapped-optional-type → type-!-
協(xié)議組合類型
協(xié)議組合類型表述的是一個符合指定的協(xié)議列表中的每個協(xié)議的類型画畅。協(xié)議組合類型可能被用在類型注解與泛型參數(shù)中哥攘。
協(xié)議組合類型有下列形式:protocol<Protocol 1, Procotol 2>
協(xié)議組合類型允許你指定一個值,該值的類型遵循多個協(xié)議的條件而不必顯示的定義一個新的命名型的繼承自每個你想要該類型遵循的協(xié)議的協(xié)議聪黎。比如蔗喂,指定一個協(xié)議組成類型protocol<Protocol A, Protocol B, Protocol C>
實際上是和定義一個新的繼承自Protocol A 忘渔, Protocol B , Protocol C
的協(xié)議組合類型Protocol D
缰儿,但不需要引入不需引入一個新名字畦粮。協(xié)議合成列表中的每項必須是協(xié)議名或協(xié)議合成類型的類型別名。如果列表為空乖阵,它就會指定一個空協(xié)議合成列表宣赔,這樣每個類型都能遵循。
協(xié)議合成列表中的每一項必須是協(xié)議名或協(xié)議組合類型的類型別名瞪浸。如果列表為空儒将,它指定一個每個類型都能遵循的空協(xié)議組合列表。
GRAMMAR OF A PROTOCOL COMPOSITION TYPEprotocol-composition-type → protocol-<-protocol-identifier-list -opt->-protocol-identifier-list → protocol-identifier- | protocol-identifier -, -protocol-identifier-list-protocol-identifier → type-identifier-
元類型類型
元類型類型指的是所有類型的類型钩蚊,包括類類型、結(jié)構(gòu)體類型蹈矮、枚舉類型和協(xié)議類型砰逻。類、結(jié)構(gòu)體或枚舉類型的元類型是緊跟.Type
的類型的名字 泛鸟。協(xié)議類型的元類型—并不是運行時遵循該協(xié)議的具體類型—是緊跟.Protocol
的該協(xié)議名字蝠咆。例如,類類型SomeClass
的元類型就是SomeClass.Type
北滥,協(xié)議類型SomeProtocol
的元類型就是SomeProtocal.Protocol
刚操。
你可以使用后綴self
表達(dá)式來獲取類型作為一個值。比如碑韵,SomeClass.self
返回SomeClass
本身赡茸,而不是SomeClas 的一個實例。并且SomeProtocol.self
返回SomeProtocol
本身祝闻,而不是運行時遵循SomeProtocol
的某個類型的實例占卧。你可以對類型的實例使用dynamicType
表達(dá)式來獲取該實例的動態(tài)運行時的類型遗菠,如下例所示:
class SomeBaseClass { class func printClassName() { print("SomeBaseClass") }}class SomeSubClass: SomeBaseClass { override class func printClassName() { print("SomeSubClass") }}let someInstance: SomeBaseClass = SomeSubClass()// The compile-time type of someInstance is SomeBaseClass,// and the runtime type of someInstance is SomeSubClasssomeInstance.dynamicType.printClassName()// Prints "SomeSubClass"
可以使用恒等運算符(===
和!==
)來測試一個實例的運行時類型和它的編譯時類型是否一致。if someInstance.dynamicType === someInstance.self { print("The dynamic type of someInstance is SomeBaseCass")} else { print("The dynamic type of someInstance isn't SomeBaseClass")}// prints "The dynamic type of someInstance isn't SomeBaseClass"
使用初始化表達(dá)式從類型的元類型的值構(gòu)造出類型的實例华蜒。對于類實例辙纬,必須用required
關(guān)鍵字標(biāo)記被調(diào)用的構(gòu)造器或者使用final
關(guān)鍵字標(biāo)記整個類。class AnotherSubClass: SomeBaseClass { let string: String required init(string: String) { self.string = string} override class func printClassName() { print("AnotherSubClass")}}let metatype: AnotherSubClass.Type = AnotherSubClass.selflet anotherInstance = metatype.init(string: "some string")
GRAMMAR OF A METATYPE TYPEmetatype-type → type-.Type- | type-.-Protocol-
類型繼承語句
類型繼承語句被用來指定一個命名型類型繼承哪個類和遵循的哪些協(xié)議叭喜。類型繼承語句也用來指定協(xié)議的class
條件贺拣。類型繼承語句開始于冒號(:
),其后是class
條件或類型標(biāo)識符列表或者兩者均有捂蕴。
類類型可以繼承單個超類譬涡,遵循任意個協(xié)議。當(dāng)定義一個類時啥辨,超類的名字必須出現(xiàn)在類型標(biāo)識符列表第一位涡匀,其后跟隨該類必須遵循的任意個協(xié)議。如果一個類不繼承自其他類溉知,列表能夠以協(xié)議開頭陨瘩。關(guān)于類繼承更多的討論和示例,參閱Inheritance级乍。
其它命名型類型可能只繼承或遵循一個協(xié)議列表舌劳。協(xié)議類型可能繼承于任意個其它協(xié)議。當(dāng)一個協(xié)議類型繼承于其它協(xié)議時玫荣,那些其它協(xié)議的條件集合會被整合在一起甚淡,任何繼承自當(dāng)前協(xié)議的類型必須遵循所有這些條件。正如協(xié)議聲明中討論的那樣崇决,可以將class
關(guān)鍵字作為第一項包含在類型繼承語句中來標(biāo)記一個附有class
條件的協(xié)議聲明材诽。
類型繼承語句在枚舉定義中可以是協(xié)議列表或者是當(dāng)枚舉賦值原始值給它的情況時的一個指定那些原始值的類型的一個單個的命名型類型底挫。使用類型繼承語句來指定其原始值類型的枚舉定義的例子恒傻,參閱Raw Values。
GRAMMAR OF A TYPE INHERITANCE CLAUSEtype-inheritance-clause → :-class-requirement-,-type-inheritance-list-type-inheritance-clause → :-class-requirement-type-inheritance-clause → :-type-inheritance-list-type-inheritance-list → type-identifier- | type-identifier-,-type-inheritance-list-class-requirement → class
類型推斷
Swift廣泛的使用類型推斷建邓,允許你在你的代碼中忽略很多變量和表達(dá)式的類型或部分類型盈厘。比如,你可以寫成var x = 0
官边,完全忽略類型沸手,而不是寫var x: Int = 0
—編譯器會正確的推斷出x
是一個類型為Int
的值的名字 。類似的注簿,當(dāng)整個類型可以從上下文推斷出來時你可以忽略類型的一部分契吉。例如,如果你寫let dict: Dictionary = ["A":1]
诡渴,編譯器推斷dict的類型是Dictionary<String, Int>
捐晶。
上面的兩個例子中,類型信息從表達(dá)式樹的葉節(jié)點向上傳向根節(jié)點。就是說惑灵,var x: Int= 0
中x
的類型首先根據(jù)0
的類型進(jìn)行推斷然后將該類型信息傳遞到根節(jié)點(變量x
)山上。
在Swift中,類型信息也可以反方向流動——從根節(jié)點向下傳向葉子節(jié)點英支。下面的示例中佩憾,例如,常量eFloat
的顯式類型注釋(:Float)
導(dǎo)致數(shù)字字面量2.71828擁有類型是Float
而不是Double
干花。let e = 2.71828 // The type of e is inferred to be Double.let eFloat: Float = 2.71828 // The type of eFloat is Float.
Swift中的類型推斷操作在單獨的表達(dá)式或語句的級別妄帘。這意味所有用于推斷省略的類型或表達(dá)式中的類型所必需的信息必須可以從表達(dá)式或其子表達(dá)式中的某個表達(dá)式的類型檢查中獲取。