1. 程式人生 > >Swift 語言附註 類型

Swift 語言附註 類型

UNC 指定 類型 基礎類型 適配 柯裏化 onu numbers 返回值

本頁包括內容:

類型註解(Type Annotation)

類型標識符(Type Identifier)

元組類型(Tuple Type)

函數類型(Function Type)

數組類型(Array Type)

可選類型(Optional Type)

隱式解析可選類型(Implicitly Unwrapped Optional Type)

協議合成類型(Protocol Composition Type)

元類型(Metatype Type)

類型繼承子句(Type Inheritance Clause)

類型判斷(Type Inference)

Swift 語言存在兩種類型:命名型類型和復合型類型。

命名型類型是指定義時能夠給定名字的類型。命名型類型包括類、結構體、枚舉和協議。比方,一個用戶定義的類MyClass的實例擁有類型MyClass。

除了用戶定義的命名型類型,Swift 標準庫也定義了非常多經常使用的命名型類型,包括那些表示數組、字典和可選值的類型。

那些通常被其他語言覺得是基本或0基礎的數據型類型(Data types)——比方表示數字、字符和字符串——實際上就是命名型類型,Swift 標準庫是使用結構體定義和實現它們的。由於它們是命名型類型,因此你能夠依照“擴展擴展聲明”章節裏討論的那樣,聲明一個擴展來添加它們的行為以適應你程序的需求。

復合型類型是沒有名字的類型。它由 Swift 本身定義。Swift 存在兩種復合型類型:函數類型和元組類型。一個復合型類型能夠包括命名型類型和其他復合型類型。比如,元組類型(Int, (Int, Int))包括兩個元素:第一個是命名型類型Int。第二個是還有一個復合型類型(Int, Int).

本節討論 Swift 語言本身定義的類型,並描寫敘述 Swift 中的類型判斷行為。

類型的語法:

type array-type- | function-type- | type-identifier- | tuple-type- | optional-type- | implicitly-unwrapped-optional-type

- | protocol-composition-type- | metatype-type-

類型註解

類型註解顯式地指定一個變量或表達式的值。類型註解始於冒號:最終類型,比方以下兩個樣例:

  1. let someTuple:(Double, Double) = (3.14159, 2.71828)
  2. func someFunction(a: Int){ /* ... */ }

在第一個樣例中。表達式someTuple的類型被指定為(Double, Double)。在第二個樣例中。函數someFunction的參數a的類型被指定為Int。

類型註解能夠在類型之前包括一個類型特性(type attributes)的可選列表。

類型註解的語法: type-annotation :-attributes-opt-type

類型標識符

類型標識符引用命名型類型或者是命名型/復合型類型的別名。

大多數情況下。類型標識符引用的是同名的命名型類型。比如類型標識符Int引用命名型類型Int。相同。類型標識符Dictionary<String, Int>引用命名型類型Dictionary<String, Int>。

在兩種情況下類型標識符引用的不是同名的類型。情況一。類型標識符引用的是命名型/復合型類型的類型別名。比方。在以下的樣例中,類型標識符使用Point來引用元組(Int, Int):

  1. typealias Point = (Int, Int)
  2. let origin: Point = (0, 0)

情況二,類型標識符使用dot(.)語法來表示在其他模塊(modules)或其他類型嵌套內聲明的命名型類型。比如。以下樣例中的類型標識符引用在ExampleModule模塊中聲明的命名型類型MyType:

  1. var someValue: ExampleModule.MyType

類型標識符的語法:

type-identifier type-name-generic-argument-clause-opt- type-name-generic-argument-clause-opt-.-type-identifier-

type-name identifier

元組類型

元組類型使用逗號隔開並使用括號括起來的0個或多個類型組成的列表。

你能夠使用元組類型作為一個函數的返回類型。這樣就能夠使函數返回多個值。你也能夠命名元組類型中的元素,然後用這些名字來引用每一個元素的值。元素的名字由一個標識符和:組成。“函數和多返回值”章節裏有一個展示上述特性的樣例。

void是空元組類型()的別名。假設括號內僅僅有一個元素,那麽該類型就是括號內元素的類型。

比方。(Int)的類型是Int而不是(Int)。所以,僅僅有當元組類型包括兩個元素以上時才幹夠標記元組元素。

元組類型語法:

tuple-type (-tuple-type-body-opt-)-

tuple-type-body tuple-type-element-list-...-opt-

tuple-type-element-list tuple-type-element- tuple-type-element-,-tuple-type-element-list-

tuple-type-element attributes-opt-inout-opt-type- inout-opt-element-name-type-annotation-

element-name identifier-

函數類型

函數類型表示一個函數、方法或閉包的類型,它由一個參數類型和返回值類型組成。中間用箭頭->隔開:

  1. parameter type -> return type

由於 參數類型 和 返回值類型 能夠是元組類型。所以函數類型能夠讓函數與方法支持多參數與多返回值。

你能夠對函數類型應用帶有參數類型()並返回表達式類型的auto_closure屬性(見類型屬性章節)。一個自己主動閉包函數捕獲特定表達式上的隱式閉包而非表達式本身。以下的樣例使用auto_closure屬性來定義一個非常easy的assert函數:

  1. func simpleAssert(condition: @auto_closure () -> Bool, message: String){
  2. if !condition(){
  3. println(message)
  4. }
  5. }
  6. let testNumber = 5
  7. simpleAssert(testNumber % 2 == 0, "testNumber isn‘t an even number.")
  8. // prints "testNumber isn‘t an even number."

函數類型能夠擁有一個可變長參數作為參數類型中的最後一個參數。從語法角度上講,可變長參數由一個基礎類型名字和...組成,如Int...。可變長參數被覺得是一個包括了基礎類型元素的數組。即Int...就是Int[]。關於使用可變長參數的樣例。見章節“可變長參數”。

為了指定一個in-out參數,能夠在參數類型前加inout前綴。

可是你不能夠對可變長參數或返回值類型使用inout。關於In-Out參數的討論見章節In-Out參數部分。

柯裏化函數(curried function)的類型相當於一個嵌套函數類型。

比如,以下的柯裏化函數addTwoNumber()()的類型是Int -> Int -> Int:

  1. func addTwoNumbers(a: Int)(b: Int) -> Int{
  2. return a + b
  3. }
  4. addTwoNumbers(4)(5) // returns 9

柯裏化函數的函數類型從右向左組成一組。

比如,函數類型Int -> Int -> Int能夠被理解為Int -> (Int -> Int)——也就是說。一個函數傳入一個Int然後輸出作為還有一個函數的輸入。然後又返回一個Int。

比如。你能夠使用例如以下嵌套函數來重寫柯裏化函數addTwoNumbers()():

  1. func addTwoNumbers(a: Int) -> (Int -> Int){
  2. func addTheSecondNumber(b: Int) -> Int{
  3. return a + b
  4. }
  5. return addTheSecondNumber
  6. }
  7. addTwoNumbers(4)(5) // Returns 9

函數類型的語法:

function-type type-->-type-

數組類型

Swift語言使用類型名緊接中括號[]來簡化標準庫中定義的命名型類型Array<T>。換句話說,以下兩個聲明是等價的:

  1. let someArray: String[] = ["Alex", "Brian", "Dave"]
  2. let someArray: Array<String> = ["Alex", "Brian", "Dave"]

上面兩種情況下,常量someArray都被聲明為字符串數組。數組的元素也能夠通過[]獲取訪問:someArray[0]是指第0個元素“Alex”。

上面的樣例同一時候顯示。你能夠使用[]作為初始值構造數組,空的[]則用來來構造指定類型的空數組。

  1. var emptyArray: Double[] = []

你也能夠使用鏈接起來的多個[]集合來構造多維數組。比如。下例使用三個[]集合來構造三維整型數組:

  1. var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

訪問一個多維數組的元素時。最左邊的下標指向最外層數組的對應位置元素。接下來往右的下標指向第一層嵌入的對應位置元素。依次類推。這就意味著,在上面的樣例中,array3D[0]是指[[1, 2], [3, 4]],array3D[0][1]是指[3, 4]。array3D[0][1][1]則是指值4。

關於Swift標準庫中Array類型的細節討論。見章節Arrays

數組類型的語法:array-type type-[-]- array-type-[-]-

可選類型

Swift定義後綴?

來作為標準庫中的定義的命名型類型Optional<T>的簡寫。換句話說,以下兩個聲明是等價的:

  1. var optionalInteger: Int?
  2. var optionalInteger: Optional<Int>

在上述兩種情況下,變量optionalInteger都被聲明為可選整型類型。註意在類型和?之間沒有空格。

類型Optional<T>是一個枚舉,有兩種形式,None和Some(T),又來代表可能出現或可能不出現的值。隨意類型都能夠被顯式的聲明(或隱式的轉換)為可選類型。

當聲明一個可選類型時。確保使用括號給?提供合適的作用範圍。比方說。聲明一個整型的可選數組,應寫作(Int[])?。寫成Int[]?的話則會出錯。

假設你在聲明或定義可選變量或特性的時候沒有提供初始值,它的值則會自己主動賦成缺省值nil。

可選符合LogicValue協議,因此能夠出如今布爾值環境下。

此時。假設一個可選類型T?

實例包括有類型為T的值(也就是說值為Optional.Some(T)),那麽此可選類型就為true,否則為false。

假設一個可選類型的實例包括一個值,那麽你就能夠使用後綴操作符!來獲取該值,正如以下描寫敘述的:

  1. optionalInteger = 42
  2. optionalInteger! // 42

使用!操作符獲取值為nil的可選項會導致執行錯誤(runtime error)。

你也能夠使用可選鏈和可選綁定來選擇性的執行可選表達式上的操作。

假設值為nil,不會執行不論什麽操作因此也就沒有執行錯誤產生。

很多其他細節以及很多其他怎樣使用可選類型的樣例,見章節“可選”。

可選類型語法:optional-type type-?

-

隱式解析可選類型

Swift語言定義後綴!作為標準庫中命名類型ImplicitlyUnwrappedOptional<T>的簡寫。換句話說,以下兩個聲明等價:

  1. var implicitlyUnwrappedString: String!
  2. var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>

上述兩種情況下,變量implicitlyUnwrappedString被聲明為一個隱式解析可選類型的字符串。註意類型與!之間沒有空格。

你能夠在使用可選的地方相同使用隱式解析可選。比方,你能夠將隱式解析可選的值賦給變量、常量和可選特性,反之亦然。

有了可選,你在聲明隱式解析可選變量或特性的時候就不用指定初始值。由於它有缺省值nil。

由於隱式解析可選的值會在使用時自己主動解析,所以不是必需使用操作符!來解析它。也就是說,假設你使用值為nil的隱式解析可選,就會導致執行錯誤。

使用可選鏈會選擇性的執行隱式解析可選表達式上的某一個操作。

假設值為nil,就不會執行不論什麽操作,因此也不會產生執行錯誤。

關於隱式解析可選的很多其他細節,見章節“隱式解析可選”。

隱式解析可選的語法:implicitly-unwrapped-optional-type type-!-

協議合成類型

協議合成類型是一種符合每一個協議的指定協議列表類型。協議合成類型可能會用在類型註解和泛型參數中。

協議合成類型的形式例如以下:

  1. protocol<Protocol 1, Procotol 2>

協議合成類型同意你指定一個值,其類型能夠適配多個協議的條件。並且不須要定義一個新的命名型協議來繼承其他想要適配的各個協議。

比方,協議合成類型protocol<Protocol A, Protocol B, Protocol C>等效於一個從Protocol A,Protocol B, Protocol C繼承而來的新協議Protocol D,非常顯然這樣做有效率的多,甚至不需引入一個新名字。

協議合成列表中的每項必須是協議名或協議合成類型的類型別名。

假設列表為空。它就會指定一個空協議合成列表。這樣每一個類型都能適配。

協議合成類型的語法:

protocol-composition-type protocol-<-protocol-identifier-list-opt->-

protocol-identifier-list protocol-identifier- protocol-identifier-,-protocol-identifier-list-

protocol-identifier type-identifier-

元類型

元類型是指全部類型的類型,包括類、結構體、枚舉和協議。

類、結構體或枚舉類型的元類型是對應的類型名緊跟.Type。協議類型的元類型——並非執行時適配該協議的詳細類型——是該協議名字緊跟.Protocol。

比方,類SomeClass的元類型就是SomeClass.Type,協議SomeProtocol的元類型就是SomeProtocal.Protocol。

你能夠使用後綴self表達式來獲取類型。

比方。SomeClass.self返回SomeClass本身。而不是SomeClass的一個實例。

相同,SomeProtocol.self返回SomeProtocol本身,而不是執行時適配SomeProtocol的某個類型的實例。

還能夠對類型的實例使用dynamicType表達式來獲取該實例在執行階段的類型,例如以下所看到的:

  1. class SomeBaseClass {
  2. class func printClassName() {
  3. println("SomeBaseClass")
  4. }
  5. }
  6. class SomeSubClass: SomeBaseClass {
  7. override class func printClassName() {
  8. println("SomeSubClass")
  9. }
  10. }
  11. let someInstance: SomeBaseClass = SomeSubClass()
  12. // someInstance is of type SomeBaseClass at compile time, but
  13. // someInstance is of type SomeSubClass at runtime
  14. someInstance.dynamicType.printClassName()
  15. // prints "SomeSubClass

元類型的語法: metatype-type type-.-Type- type-.-Protocol

類型繼承子句

類型繼承子句被用來指定一個命名型類型繼承哪個類且適配哪些協議。

類型繼承子句開始於冒號:。緊跟由,隔開的類型標識符列表。

類能夠繼承單個超類,適配隨意數量的協議。

當定義一個類時,超類的名字必須出如今類型標識符列表首位。然後跟上該類須要適配的隨意數量的協議。假設一個類不是從其他類繼承而來,那麽列表能夠以協議開頭。關於類繼承很多其他的討論和樣例,見章節“繼承”。

其他命名型類型可能僅僅繼承或適配一個協議列表。協議類型可能繼承於其他隨意數量的協議。

當一個協議類型繼承於其他協議時,其他協議的條件集合會被集成在一起,然後其他從當前協議繼承的隨意類型必須適配全部這些條件。

枚舉定義中的類型繼承子句能夠是一個協議列表,或是指定原始值的枚舉,一個單獨的指定原始值類型的命名型類型。使用類型繼承子句來指定原始值類型的枚舉定義的樣例,見章節“原始值”。

類型繼承子句的語法:

type-inheritance-clause :-type-inheritance-list

type-inheritance-list type-identifier- type-identifier-,-type-inheritance-list-



類型判斷

Swift廣泛的使用類型判斷,從而同意你能夠忽略非常多變量和表達式的類型或部分類型。比方,對於var x: Int = 0,你能夠全然忽略類型而簡寫成var x = 0——編譯器會正確的判斷出x的類型Int。

相似的,當完整的類型能夠從上下文判斷出來時,你也能夠忽略類型的一部分。比方,假設你寫了let dict: Dictionary = ["A": 1],編譯提也能判斷出dict的類型是Dictionary<String, Int>。

在上面的兩個樣例中。類型信息從表達式樹(expression tree)的葉子節點傳向根節點。也就是說,var x: Int = 0中x的類型首先依據0的類型進行判斷,然後將該類型信息傳遞到根節點(變量x)。

在Swift中,類型信息也能夠反方向流動——從根節點傳向葉子節點。在以下的樣例中。常量eFloat上的顯式類型註解(:Float)導致數字字面量2.71828的類型是Float而非Double。

  1. let e = 2.71828 // The type of e is inferred to be Double.
  2. let eFloat: Float = 2.71828 // The type of eFloat is Float.

Swift中的類型判斷在單獨的表達式或語句水平上進行。這意味著全部用於判斷類型的信息必須能夠從表達式或其某個子表達式的類型檢查中獲取。

Swift 語言附註 類型