Swift數據類型簡介(二)


整數

整數就是沒有小數部分的數字,比如42和-23。整數可以是有符號(正、負、零)或者無符號(正、零)。

Swift 提供了8,16,32和64位的有符號和無符號整數類型。這些整數類型和 C 語言的命名方式很像,比如8位無符號整數類型是UInt8,32位有符號整數類型是Int32。就像 Swift 的其他類型一樣,整數類型采用大寫命名法。

整數范圍

你可以訪問不同整數類型的min和max屬性來獲取對應類型的最大值和最小值:

  1. let minValue = UInt8.min // minValue 為 0,是 UInt8 類型的最小值
  2. let maxValue = UInt8.max // maxValue 為 255,是 UInt8 類型的最大值

Int

一般來說,你不需要專門指定整數的長度。Swift 提供了一個特殊的整數類型Int,長度與當前平台的原生字長相同:

  • 在32位平台上,Int和Int32長度相同。
  • 在64位平台上,Int和Int64長度相同。


除非你需要特定長度的整數,一般來說使用Int就夠了。這可以提高代碼一致性和可復用性。即使是在32位平台上,Int可以存儲的整數范圍也可以達到-2147483648~2147483647,大多數時候這已經足夠大了。

UInt

Swift 也提供了一個特殊的無符號類型UInt,長度與當前平台的原生字長相同:

  • 在32位平台上,UInt和UInt32長度相同。
  • 在64位平台上,UInt和UInt64長度相同。
注意:盡量不要使用UInt,除非你真的需要存儲一個和當前平台原生字長相同的無符號整數。除了這種情況,最好使用Int,即使你要存儲的值已知是非負的。統一使用Int可以提高代碼的可復用性,避免不同類型數字之間的轉換,並且匹配數字的類型推測,請參考 類型安全和類型推測

浮點數

浮點數是有小數部分的數字,比如3.14159,0.1和-273.15。

浮點類型比整數類型表示的范圍更大,可以存儲比Int類型更大或者更小的數字。Swift 提供了兩種有符號浮點數類型:

  • Double表示64位浮點數。當你需要存儲很大或者很高精度的浮點數時請使用此類型。
  • Float表示32位浮點數。精度要求不高的話可以使用此類型。
注意:Double精確度很高,至少有15位數字,而Float最少只有6位數字。選擇哪個類型取決於你的代碼需要處理的值的范圍。

類型安全和類型推測

Swift 是一個類型安全(type safe )的語言。類型安全的語言可以讓你清楚地知道代碼要處理的值的類型。如果你的代碼需要一個String,你絕對不可能不小心傳進去一個Int。

由於 Swift 是類型安全的,所以它會在編譯你的代碼時進行類型檢查(type checks),並把不匹配的類型標記為錯誤。這可以讓你在開發的時候盡早發現並修復錯誤。

當你要處理不同類型的值時,類型檢查可以幫你避免錯誤。然而,這並不是說你每次聲明常量和變量的時候都需要顯式指定類型。如果你沒有顯式指定類 型,Swift 會使用類型推測(type inference)來選擇合適的類型。有了類型推測,編譯器可以在編譯代碼的時候自動推測出表達式的類型。原理很簡單,只要檢查你賦的值即可。

因為有類型推測,和 C 或者 Objective-C 比起來 Swift 很少需要聲明類型。常量和變量雖然需要明確類型,但是大部分工作並不需要你自己來完成。

當你聲明常量或者變量並賦初值的時候類型推測非常有用。當你在聲明常量或者變量的時候賦給它們一個字面量(literal value 或 literal)即可觸發類型推測。(字面量就是會直接出現在你代碼中的值,比如42和3.14159。)

例如,如果你給一個新常量賦值42並且沒有標明類型,Swift 可以推測出常量類型是Int,因為你給它賦的初始值看起來像一個整數:

  1. let meaningOfLife = 42 // meaningOfLife 會被推測為 Int 類型

同理,如果你沒有給浮點字面量標明類型,Swift 會推測你想要的是Double:

  1. let pi = 3.14159 // pi 會被推測為 Double 類型

當推測浮點數的類型時,Swift 總是會選擇Double而不是Float。

如果表達式中同時出現了整數和浮點數,會被推測為Double類型:

  1. let anotherPi = 3 + 0.14159 // anotherPi 會被推測為 Double 類型

原始值3沒有顯式聲明類型,而表達式中出現了一個浮點字面量,所以表達式會被推測為Double類型。

數值型字面量

整數字面量可以被寫作:

  • 一個十進制數,沒有前綴
  • 一個二進制數,前綴是0b
  • 一個八進制數,前綴是0o
  • 一個十六進制數,前綴是0x


下面的所有整數字面量的十進制值都是17:

  1. let decimalInteger = 17
  2. let binaryInteger = 0b10001 // 二進制的17
  3. let octalInteger = 0o21 // 八進制的17
  4. let hexadecimalInteger = 0x11 // 十六進制的17

浮點字面量可以是十進制(沒有前綴)或者是十六進制(前綴是0x)。小數點兩邊必須有至少一個十進制數字(或者是十六進制的數字)。浮點字面量還有一個可 選的指數(exponent),在十進制浮點數中通過大寫或者小寫的e來指定,在十六進制浮點數中通過大寫或者小寫的p來指定。

如果一個十進制數的指數為exp,那這個數相當於基數和$10^{exp}$的乘積:

  • 1.25e2 表示 $1.25 × 10^{2}$,等於 125.0。
  • 1.25e-2 表示 $1.25 × 10^{-2}$,等於 0.0125。


如果一個十六進制數的指數為exp,那這個數相當於基數和$2^{exp}$的乘積:

  • 0xFp2 表示 $15 × 2^{2}$,等於 60.0。
  • 0xFp-2 表示 $15 × 2^{-2}$,等於 3.75。


下面的這些浮點字面量都等於十進制的12.1875:

  1. let decimalDouble = 12.1875
  2. let exponentDouble = 1.21875e1
  3. let hexadecimalDouble = 0xC.3p0

數值類字面量可以包括額外的格式來增強可讀性。整數和浮點數都可以添加額外的零並且包含下划線,並不會影響字面量:

  1. let paddedDouble = 000123.456
  2. let oneMillion = 1_000_000
  3. let justOverOneMillion = 1_000_000.000_000_1

數值型類型轉換

通常來講,即使代碼中的整數常量和變量已知非負,也請使用Int類型。總是使用默認的整數類型可以保證你的整數常量和變量可以直接被復用並且可以匹配整數 類字面量的類型推測。 只有在必要的時候才使用其他整數類型,比如要處理外部的長度明確的數據或者為了優化性能、內存占用等等。使用顯式指定長度的類型可以及時發現值溢出並且可 以暗示正在處理特殊數據。

整數轉換

不同整數類型的變量和常量可以存儲不同范圍的數字。Int8類型的常量或者變量可以存儲的數字范圍是-128~127,而UInt8類型的常量或者變量能存儲的數字范圍是0~255。如果數字超出了常量或者變量可存儲的范圍,編譯的時候會報錯:

  1. let cannotBeNegative: UInt8 = -1 // UInt8 類型不能存儲負數,所以會報錯
  2. let tooBig: Int8 = Int8.max + 1 // Int8 類型不能存儲超過最大值的數,所以會報錯

由於每中整數類型都可以存儲不同范圍的值,所以你必須根據不同情況選擇性使用數值型類型轉換。這種選擇性使用的方式,可以預防隱式轉換的錯誤並讓你的代碼中的類型轉換意圖變得清晰。

要將一種數字類型轉換成另一種,你要用當前值來初始化一個期望類型的新數字,這個數字的類型就是你的目標類型。在下面的例子中,常量 twoThousand是UInt16類型,然而常量one是Uint8類型。它們不能直接相加,因為它們類型不同。所以要調用UInt16(one)來 創建一個新的UInt16數字並用one的值來初始化,然后使用這個新數字來計算:

  1. let twoThousand: UInt16 = 2_000
  2. let one: UInt8 = 1
  3. let twoThousandAndOne = twoThousand + UInt16(one)

現在兩個數字的類型都是UInt16,可以進行相加。目標常量twoThousandAndOne的類型被推測為UInt16,因為它是兩個UInt16值的和。

SomeType(ofInitialValue)是調用 Swift 構造器並傳入一個初始值的默認方法。在語言內部,UInt16有一個構造器,可以接受一個UInt8類型的值,所以這個構造器可以用現有的UInt8來創 建一個新的UInt16。注意,你並不能傳入任意類型的值,只能傳入UInt16內部有對應構造器的值。不過你可以擴展現有的類型來讓它可以接收其他類型 的值(包括自定義類型),請參考擴展

整數和浮點數轉換

整數和浮點數的轉換必須顯式指定類型:

  1. let three = 3
  2. let pointOneFourOneFiveNine = 0.14159
  3. let pi = Double(three) + pointOneFourOneFiveNine
  4. // pi 等於 3.14159,所以被推測為 Double 類型

這個例子中,常量three的值被用來創建一個Double類型的值,所以加號兩邊的數類型相同。如果不進行轉換,兩者無法相加。

浮點數到整數的反向轉換同樣行,整數類型可以用Double或者Float類型來初始化:

  1. let integerPi = Int(pi) // integerPi 等於 3,所以被推測為 Int 類型

當用這種方式來初始化一個新的整數值時,浮點值會被截斷。也就是說4.75會變成4,-3.9會變成-3。

注意:結合數字類常量和變量不同於結合數字類字面量。字面量3可以直接和字面量0.14159相加,因為數字字面量本身沒有明確的類型。它們的類型只在編譯器需要求值的時候被推測。

類型別名

類型別名(type aliases)就是給現有類型定義另一個名字。你可以使用typealias關鍵字來定義類型別名。

當你想要給現有類型起一個更有意義的名字時,類型別名非常有用。假設你正在處理特定長度的外部資源的數據:

  1. typealias AudioSample = UInt16

定義了一個類型別名之后,你可以在任何使用原始名的地方使用別名:

  1. var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 現在是 0

本例中,AudioSample被定義為UInt16的一個別名。因為它是別名,AudioSample.min實際上是UInt16.min,所以會給maxAmplitudeFound賦一個初值0。

布爾值

Swift 有一個基本的布爾(Boolean)類型,叫做Bool。布爾值指邏輯上的(logical),因為它們只能是真或者假。Swift 有兩個布爾常量,true和false:

  1. let orangesAreOrange = true
  2. let turnipsAreDelicious = false

orangesAreOrange和turnipsAreDelicious的類型會被推測為Bool,因為它們的初值是布爾字面量。就像之前提到的 Int和Double一樣,如果你創建變量的時候給它們賦值true或者false,那你不需要將常量或者變量聲明為Bool類型。初始化常量或者變量的 時候如果所賦的值類型已知,就可以觸發類型推測,這讓 Swift 代碼更加簡潔並且可讀性更高。

當你編寫條件語句比如if語句的時候,布爾值非常有用:

  1. if turnipsAreDelicious {
  2. println("Mmm, tasty turnips!")
  3. } else {
  4. println("Eww, turnips are horrible.")
  5. }
  6. // 輸出 "Eww, turnips are horrible."

條件語句,例如if,請參考控制流

如果你在需要使用Bool類型的地方使用了非布爾值,Swift 的類型安全機制會報錯。下面的例子會報告一個編譯時錯誤:

  1. let i = 1 if i { // 這個例子不會通過編譯,會報錯 }

然而,下面的例子是合法的:

  1. let i = 1 if i == 1 { // 這個例子會編譯成功 }

i == 1的比較結果是Bool類型,所以第二個例子可以通過類型檢查。類似i == 1這樣的比較,請參考基本操作符

和 Swift 中的其他類型安全的例子一樣,這個方法可以避免錯誤並保證這塊代碼的意圖總是清晰的。

元組

元組(tuples)把多個值組合成一個復合值。元組內的值可以使任意類型,並不要求是相同類型。

下面這個例子中,(404, "Not Found")是一個描述 HTTP 狀態碼(HTTP status code)的元組。HTTP 狀態碼是當你請求網頁的時候 web 服務器返回的一個特殊值。如果你請求的網頁不存在就會返回一個404 Not Found狀態碼。

  1. let http404Error = (404, "Not Found") // http404Error 的類型是 (Int, String),值是 (404, "Not Found")

(404, "Not Found")元組把一個Int值和一個String值組合起來表示 HTTP 狀態碼的兩個部分:一個數字和一個人類可讀的描述。這個元組可以被描述為“一個類型為(Int, String)的元組”。

你可以把任意順序的類型組合成一個元組,這個元組可以包含所有類型。只要你想,你可以創建一個類型為(Int, Int, Int)或者(String, Bool)或者其他任何你想要的組合的元組。

你可以將一個元組的內容分解(decompose)成單獨的常量和變量,然后你就可以正常使用它們了:

  1. let (statusCode, statusMessage) = http404Error
  2. println("The status code is \(statusCode)")
  3. // 輸出 "The status code is 404"
  4. println("The status message is \(statusMessage)")
  5. // 輸出 "The status message is Not Found"

如果你只需要一部分元組值,分解的時候可以把要忽略的部分用下划線(_)標記:

  1. let (justTheStatusCode, _) = http404Error
  2. println("The status code is \(justTheStatusCode)")
  3. // 輸出 "The status code is 404"

此外,你還可以通過下標來訪問元組中的單個元素,下標從零開始:

  1. println("The status code is \(http404Error.0)") // 輸出 "The status code is 404"
  2. println("The status message is \(http404Error.1)") // 輸出 "The status message is Not Found"

你可以在定義元組的時候給單個元素命名:

  1. let http200Status = (statusCode: 200, description: "OK")

給元組中的元素命名后,你可以通過名字來獲取這些元素的值:

  1. println("The status code is \(http200Status.statusCode)") // 輸出 "The status code is 200"
  2. println("The status message is \(http200Status.description)") // 輸出 "The status message is OK"

作為函數返回值時,元組非常有用。一個用來獲取網頁的函數可能會返回一個(Int, String)元組來描述是否獲取成功。和只能返回一個類型的值比較起來,一個包含兩個不同類型值的元組可以讓函數的返回信息更有用。請參考[函數參數與 返回值(06_Functions.html#Function_Parameters_and_Return_Values)。

注意:元組在臨時組織值的時候很有用,但是並不適合創建復雜的數據結構。如果你的數據結構並不是臨時使用,請使用類或者結構體而不是元組。請參考 類和結構體

可選

使用可選(optionals)來處理值可能缺失的情況。可選表示:

  • 有值,等於 x

或者

  • 沒有值
注意:C 和 Objective-C 中並沒有可選這個概念。最接近的是 Objective-C 中的一個特性,一個方法要不返回一個對象要不返回nil,nil表示“缺少一個合法的對象”。然而,這只對對象起作用——對於結構體,基本的 C 類型或者枚舉類型不起作用。對於這些類型,Objective-C 方法一般會返回一個特殊值(比如NSNotFound)來暗示值缺失。這種方法假設方法的調用者知道並記得對特殊值進行判斷。然而,Swift 的可選可以讓你暗示任意類型的值缺失,並不需要一個特殊值。

來看一個例子。Swift 的String類型有一個叫做toInt的方法,作用是將一個String值轉換成一個Int值。然而,並不是所有的字符串都可以轉換成一個整數。字符串"123"可以被轉換成數字123,但是字符串"hello, world"不行。

下面的例子使用toInt方法來嘗試將一個String轉換成Int:

  1. let possibleNumber = "123"
  2. let convertedNumber = possibleNumber.toInt()
  3. // convertedNumber 被推測為類型 "Int?", 或者類型 "optional Int"

因為toInt方法可能會失敗,所以它返回一個可選的(optional)Int,而不是一個Int。一個可選的Int被寫作Int?而不是Int。問號 暗示包含的值是可選,也就是說可能包含Int值也可能不包含值。(不能包含其他任何值比如Bool值或者String值。只能是Int或者什么都沒有。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM