1. 程式人生 > >swift4官方文件中文版

swift4官方文件中文版

Guards翻譯組 正在翻譯Swift 4的全套文件, 這是該文件第一章節的上半部分, 下半部分我們將於明天下午釋出. 如果你感興趣, 可以關注我們的簡書.
原文連結: The Basics

Swift 是一門開發 iOS, macOS, watchOS 和 tvOS 應用的新語言。即便如此,如果你有 C 或者 Objective-C 開發經驗,你會發現 Swift 的有很多你熟悉的內容。Swift 提供了與 C 和 Objective-C 上所有基礎資料型別,如整型Int; 浮點型Double和Float; 布林型值Bool;文字型資料String 。 Swift 還提供了三個基本的集合型別,Array ,Set和 Dictionary ,詳見集合型別。

和 C 語言類似,Swift 使用變數來進行儲存並通過變數名來關聯對應的值。在 Swift 中,不可變的變數非常常用,它們就是常量,而且比 C 語言的常量更強大。在 Swift 中,如果你要處理的值不需要改變,那使用常量可以讓你的程式碼更加安全並且更清晰地表達你的意圖。

除了我們熟悉的型別,Swift 還增加了 Objective-C 中沒有的高階資料型別, 比如元組Tuples。元組可以讓你建立或者傳遞一組資料,當函式需要返回單一複合值時,你可以用一個元組可以返回多個值。

Swift 還增加了Optional型別(譯者注: Optional型別即可選型別),用於處理值不存在的情況。可選的意思是 “這裡有一個值,並且它等於x ” 或 “這裡沒有值” 。可選有點像在 Objective-C 中使用nil ,但是它可以用在任何型別上,不僅僅是類。可選型別比 Objective-C 中的 nil指標更加安全也更具表現力,它是 Swift 許多強大特性的重要組成部分。
Swift 是一門型別安全的語言,這意味著 Swift 可以讓你清楚地知道值的型別。如果你的程式碼期望得到一個String ,型別安全會阻止你錯誤地傳入一個Int。同樣的,如果你的程式碼期望得到一個 String,型別安全會阻止你意外傳入一個可選的 String 。型別安全可以幫助你在開發階段儘早發現並修正錯誤。

常量和變數

常量和變數把一個名字(比如maximumNumberOfLoginAttempts或者 welcomeMessage)和一個指定型別的值(比如數字 10或者字串”Hello”)關聯起來。常量的值一旦設定就不能改變,而變數的值可以隨意更改。

宣告常量和變數

常量和變數必須在使用前宣告,用 關鍵字let來宣告常量和關鍵字 var來宣告變數。下面的例子展示瞭如何用常量和變數來記錄使用者嘗試登入的次數:

  let maximumNumberOfLoginAttempts = 10
  var currentLoginAttempt = 0

這兩行程式碼可以被理解為:
“宣告一個名字是maximumNumberOfLoginAttempts的新常量,並給它一個值 10。然後,宣告一個名字是currentLoginAttempt的變數並將它的值初始化為0 ”。

在這個例子中,允許的最大嘗試登入次數被宣告為一個常量,因為這個值不會改變。當前嘗試登入次數被宣告為一個變數,因為每次嘗試登入失敗的時候都需要增加這個值。
你可以在一行中宣告多個常量或者多個變數,用逗號隔開:

  var x = 0.0, y = 0.0, z = 0.0

Note:如果你的程式碼中有不需要改變的值,請使用 let 關鍵字將它宣告為常量。只將需要改變的值宣告為變數。

型別標註

當你宣告常量或者變數的時候可以加上 型別標註 (type annotation),說明常量或者變數中要儲存的值的型別。通過在常量或變數名後面接一個冒號來寫一個型別標註,後跟一個空格,後跟要使用的型別的名稱。

這個例子給welcomeMessage 變數添加了型別標註,表示這個變數可以儲存 String型別的值:

   var welcomeMessage: String

宣告中的冒號代表著“xx是xx型別”,所以這行程式碼可以被理解為:

宣告一個型別為 String,名字為welcomeMessage的變數。
型別為 String ”的意思是“可以儲存任意 String 型別的值。

welcomeMessage 變數現在可以被正確地設定成任意字串:

  welcomeMessage = "Hello"

你可以在一行中定義多個同樣型別的變數,用逗號分割,並在最後一個變數名之後新增型別標註:

  var red, green, blue: Double

Note:一般來說你很少需要寫型別標註。如果你在宣告常量或者變數的時候賦了一個初始值,Swift可以推斷出這個常量或者變數的型別,請參考型別安全和型別推斷。在上面的例子中,沒有給 welcomeMessage
賦初始值,所以變數 welcomeMessage
的型別是通過一個型別標註指定的,而不是通過初始值推斷的。
常量和變數的命名

你可以用任何你喜歡的字元作為常量和變數名,包括 Unicode 字元:

let π = 3.14159
let 你好 = "你好世界"
let  = "dogcow"

常量與變數名不能包含空格,數學符號,箭頭,保留的(或者非法的)Unicode 碼位,連線與製表符。不能以數字開頭,但是可以在常量與變數名的其他地方包含數字。
一旦你將常量或者變數宣告為確定的型別,你就不能使用相同的名字再次進行宣告,或者改變其儲存的值的型別。同時,你也不能將常量與變數進行互轉。

Note:如果你需要使用與Swift保留關鍵字相同的名稱作為常量或者變數名,你可以使用反引號(`)將關鍵字包圍的方式將其作為名字使用。無論如何,你應當避免使用關鍵字作為常量或變數名,除非你別無選擇。
你可以更改現有的變數值為其他同類型的值,在下面的例子中,friendlyWelcome的值從”Hello!”改為了”Bonjour!”:

var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome 現在是 "Bonjour!"

與變數不同,常量的值一旦被確定就不能更改了。嘗試這樣做會導致編譯時報錯:

let languageName = "Swift"
languageName = "Swift++"
// 這會報編譯時錯誤 - languageName 不可改變

輸出常量和變數

你可以用print(_:separator:terminator:)
函式來輸出當前常量或變數的值:

print(friendlyWelcome)// 輸出 "Bonjour!"

print(:separator:terminator:)是一個用來輸出一個或多個值到適當輸出區的全域性函式。在 Xcode中,print(:separator:terminator:)將會輸出內容到“console”面板上。separator和 terminator引數具有預設值,因此你呼叫這個函式的時候可以忽略它們。預設情況下,該函式通過新增換行符來結束當前行。如果不想換行,可以傳遞一個空字串給 terminator 引數–例如,print(someValue, terminator:”“)
。關於引數預設值的更多資訊,請參考預設引數值。

Swift 用字串插值(string interpolation)的方式把常量名或者變數名當做佔位符加入到長字串中,Swift 會用當前常量或變數的值替換這些佔位符。將常量或變數名放入圓括號中,並在開括號前使用反斜槓將其轉義:

print("The current value of friendlyWelcome is \(friendlyWelcome)")
// 輸出 "The current value of friendlyWelcome is Bonjour!

Note:字串插值所有可用的選項,請參考字串插值。
註釋

請將你的程式碼中的非執行文字註釋成提示或者筆記以方便你將來閱讀。Swift 的編譯器將會在編譯程式碼時自動忽略掉註釋部分。
Swift 中的註釋與 C 語言的註釋非常相似。單行註釋以雙正斜槓 (//)
作為起始標記:

  // 這是一個註釋
  ```
行註釋的起始標記為單個正斜槓後跟隨一個星號(/*),終止標記為一個星號後跟隨單個正斜槓(*/):

/* 這是一個,多行註釋 */

C 語言多行註釋不同,Swift 的多行註釋可以巢狀在其它的多行註釋之中。你可以先生成一個多行註釋塊,然後在這個註釋塊之中再巢狀成第二個多行註釋。終止註釋時先插入第二個註釋塊的終止標記,然後再插入第一個註釋塊的終止標記:

/* 這是第一個多行註釋的開頭
/* 這是第二個被巢狀的多行註釋 */
這是第一個多行註釋的結尾 */


通過運用巢狀多行註釋,你可以方便快速的註釋掉一大段程式碼,即使這段程式碼之中已經含有了多行註釋塊。

#### 分號

與其他大部分程式語言不同,Swift 並不強制要求你在每條語句的結尾處使用分號(;),當然,你也可以按照你自己的習慣新增分號。有一種情況下必須要用分號,即你打算在同一行內寫多條獨立的語句:

let cat = “”;
print(cat)// 輸出 “”

#### 整數

整數就是沒有小數部分的數字,比如 42和 -23 。整數可以是 有符號(正數、零和負數)或者無符號(正數、零)。
Swift 提供了8163264位的有符號和無符號整數型別。這些整數型別和 C 語言的命名方式很像,比如8位無符號整數型別是UInt8,32位有符號整數型別是Int32。就像 Swift 的其他型別一樣,整數型別採用大寫命名法。

#### 整數範圍

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

let minValue = UInt8.min // minValue 為 0,是 UInt8 型別
let maxValue = UInt8.max // maxValue 為 255,是 UInt8 型別

這些屬性的值具有適當大小的數字型別(例如上例中的UInt8),因此可以與表示式一起使用同一型別的其他值。

#### Int

大多數情況下,你不需要專門指定整數的長度。Swift 提供了一個特殊的整數型別Int,長度與當前平臺的原生字長相同:

在32位平臺上,Int和 Int32長度相同。
在64位平臺上,Int和 Int64長度相同。
除非你需要特定長度的整數,一般來說使用 Int就夠了。這可以提高程式碼一致性和可複用性。即使是在32位平臺上,Int 可以儲存的整數範圍也可以達到 -2,147,483,648 ~ 2,147,483,647,大多數時候這已經足夠大了。

#### UInt

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

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

浮點數是有小數部分的數字,比如 3.141590.1 和 -273.15。
浮點型別比整數型別表示的範圍更廣,可以儲存比Int
型別更大或者更小的數字。Swift 提供了兩種有符號浮點數型別:

Double表示64位浮點數。
Float表示32位浮點數。
Note:Double精確度很高,至少有15位數字,而Float只有6位數字。選擇哪個型別取決於你的程式碼需要處理的值的範圍,在兩種型別都可以選擇的情況下,將優先選擇 Double。
##### 型別安全和型別推斷

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

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

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

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

當你宣告常量或者變數並賦初值的時候型別推斷非常有用。當你在宣告常量或者變數的時候賦給它們一個確定值(literal value 或 literal)即可觸發型別推斷。(字面量就是會直接出現在你程式碼中的值,比如 423.14159。)
例如,如果你給一個新常量賦值42並且沒有標明型別,Swift 可以推斷出常量型別是 Int,因為你給它賦的初始值看起來像一個整數:

let meaningOfLife = 42// meaningOfLife 會被推測為 Int 型別

同理,如果你沒有給浮點數標明型別,Swift 會推斷你想要的是Double

let pi = 3.14159// pi 會被推測為 Double 型別

當推斷浮點數的型別時,Swift 總是會優先選擇 Double而不是Float。如果表示式中同時出現了整數和浮點數,會被推斷為 Double
型別:

let anotherPi = 3 + 0.14159 // anotherPi 會被推測為 Double 型別

原始值3 沒有顯式宣告型別,而表示式中出現了一個浮點數,所以表示式會被推斷為 Double型別。

#### 數值型字面量

整數字面量可以被寫作:

一個十進位制數,沒有字首
一個二進位制數,字首是0b
一個八進位制數,字首是0o
一個十六進位制數,字首是0x
下面的所有整數字面量的十進位制值都是17

let decimalInteger = 17
let binaryInteger = 0b10001 // 二進位制的17
let octalInteger = 0o21 // 八進位制的17
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:

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

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

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

#### 數值型型別轉換

通常來講,即使程式碼中的整數常量和變數已知非負,也請使用Int型別。總是使用預設的整數型別可以保證你的整數常量和變數可以直接被複用並且可以匹配整數類字面量的型別推斷。

只有在必要的時候才使用其他整數型別,比如要處理外部的長度明確的資料或者為了優化效能、記憶體佔用等等。使用顯式指定長度的型別可以及時發現值溢位並且可以暗示正在處理特殊資料。

##### 整數轉換

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

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

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

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

let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
“`
現在兩個數字的型別都是 UInt16,可以進行相加。輸出常量 twoThousandAndOne 的型別被推斷為 UInt16,因為它是兩個 UInt16值的和。

SomeType(ofInitialValue)是呼叫Swift型別的初始化器並傳入初始值的預設方式。
在語言內部,UInt16有接受一個UInt8的值,這個初始化器用來從現有的UInt8中建立一個新的UInt16。然而,你並不能傳入任意型別的值,只能傳入UInt16型別的值。不過你可以擴充套件現有的型別來讓它可以接收其他型別的值(包括自定義型別),請參考擴充套件。

整數和浮點數轉換

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

let three = 3let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine // pi 等於 3.14159,所以被推測為 Double 型別
這個例子中,常量 three的值被用來建立一個Double型別的值,所以加號兩邊的數型別須相同。如果不進行轉換,兩者無法相加。浮點數到整數的反向轉換同樣行,整數型別可以用` Double 或者Float型別來初始化:

let integerPi = Int(pi)// integerPi 等於 3,所以被推測為 Int 型別
當用浮點型別來初始化一個新的整數值時,浮點值會被截斷。也就是說 4.75會變成 4,-3.9會變成 -3。

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

類型別名

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

當你想要給現有型別起一個更合適的名字時,類型別名非常有用。比如你正在處理特定長度的外部資源的資料:

typealias AudioSample = UInt16

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

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

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

布林值

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

let orangesAreOrange = truelet
turnipsAreDelicious = false

orangesAreOrange和turnipsAreDelicious 的型別會被推斷為 Bool,因為它們的初值是布林字面量。就像之前提到的 Int 和 Double一樣,如果建立變數的時候給它們賦值 true或者false,那你不需要將常量或者變數宣告為Bool型別。初始化常量或者變數的時候如果所賦的值型別已知,就可以觸發型別推斷,這讓 Swift 程式碼更加簡潔並且可讀性更高。當你編寫條件語句比如 if 語句的時候,布林值非常有用:

if turnipsAreDelicious {
     print("Mmm, tasty turnips!")
} else {
     print("Eww, turnips are horrible.")
}

// 輸出 “Eww, turnips are horrible.”
條件語句,例如if,請參考控制流。

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

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

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

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 狀態碼。

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)成單獨的常量和變數,然後你就可以正常使用它們了:

let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 輸出 "The status code is 404"
print("The status message is \(statusMessage)")
// 輸出 "The status message is Not Found"

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

let (justTheStatusCode, \_) = http404Error
print("The status code is \(justTheStatusCode)")
// 輸出 "The status code is 404"

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

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

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

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

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

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

作為函式返回值時,元組非常有用。一個用來獲取網頁的函式可能會返回一個(Int, String) 元組來描述是否獲取成功。和只能返回一個型別的值比較起來,一個包含兩個不同型別值的元組可以讓函式的返回資訊更有用。請參考函式引數與返回值。

Note:元組在臨時組織值的時候很有用,但是並不適合建立複雜的資料結構。如果你的資料結構並不是臨時使用,請使用類或者結構體而不是元組。請參考類和結構體。
The Basics 上半部分完結, 下半部分我們將於明天下午釋出.