天天看點

Swift基礎文法(常量變量、資料類型、元組、可選、斷言)

本文來自swift中文開發組,感謝翻譯者的分享。

本文将分幾部分對swift對ios的文法做講解。本文為第一節,主要講解基礎文法。

常量和變量把一個名字(比如maximumnumberofloginattempts或者welcomemessage)和一個指定類型的值(比如數字10或者字元串"hello")關聯起來。常量的值一旦設定就不能改變,而變量的值可以随意更改。

常量和變量必須在使用前聲明,用let來聲明常量,用var來聲明變量。下面的例子展示了如何用常量和變量來記錄使用者嘗試登入的次數:

這兩行代碼可以被了解為:“聲明一個名字是maximumnumberofloginattempts的新常量,并給它一個值10。然後,聲明一個名字是currentloginattempt的變量并将它的值初始化為0.”

在這個例子中,允許的最大嘗試登入次數被聲明為一個常量,因為這個值不會改變。目前嘗試登入次數被聲明為一個變量,因為每次嘗試登入失敗的時候都需要增加這個值。

你可以在一行中聲明多個常量或者多個變量,用逗号隔開:

注意:如果你的代碼中有不需要改變的值,請使用let關鍵字将它聲明為常量。隻将需要改變的值聲明為變量。

當你聲明常量或者變量的時候可以加上類型标注(type annotation),說明常量或者變量中要存儲的值的類型。如果要添加類型标注,需要在常量或者變量名後面加上一個冒号和空格,然後加上類型名稱。

這個例子給welcomemessage變量添加了類型标注,表示這個變量可以存儲string類型的值:

聲明中的冒号代表着“是...類型”,是以這行代碼可以被了解為:“聲明一個類型為string,名字為welcomemessage的變量。”

“類型為string”的意思是“可以存儲任意string類型的值。”

welcomemessage變量現在可以被設定成任意字元串:

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

常量與變量名不能包含數學符号,箭頭,保留的(或者非法的)unicode 碼位,連線與制表符。也不能以數字開頭,但是可以在常量與變量名的其他地方包含數字。

一旦你将常量或者變量聲明為确定的類型,你就不能使用相同的名字再次進行聲明,或者改變其存儲的值的類型。同時,你也不能将常量與變量進行互轉。

注意:如果你需要使用與swift保留關鍵字相同的名稱作為常量或者變量名,你可以使用反引号(`)将關鍵字包圍的方式将其作為名字使用。無論如何,你應當避免使用關鍵字作為常量或變量名,除非你别無選擇。

你可以更改現有的變量值為其他同類型的值,在下面的例子中,friendlywelcome的值從"hello!"改為了"bonjour!":

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

你可以用println函數來輸出目前常量或變量的值:

println是一個用來輸出的全局函數,輸出的内容會在最後換行。如果你用 xcode,println将會輸出内容到“console”面闆上。(另一種函數叫print,唯一差別是在輸出内容最後不會換行。)

println函數輸出傳入的string值:

與 cocoa 裡的nslog函數類似的是,println函數可以輸出更複雜的資訊。這些資訊可以包含目前常量和變量的值。

swift 用字元串插值(string interpolation)的方式把常量名或者變量名當做占位符加入到長字元串中,swift 會用目前常量或變量的值替換這些占位符。将常量或變量名放入圓括号中,并在開括号前使用反斜杠将其轉義:

請将你的代碼中的非執行文本注釋成提示或者筆記以友善你将來閱讀。swift 的編譯器将會在編譯代碼時自動忽略掉注釋部分。

swift 中的注釋與c 語言的注釋非常相似。單行注釋以雙正斜杠作(//)為起始标記;

// 這是一個注釋 

你也可以進行多行注釋,其起始标記為單個正斜杠後跟随一個星号(/*),終止标記為一個星号後跟随單個正斜杠(*/)

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

與c 語言多行注釋不同,swift 的多行注釋可以嵌套在其它的多行注釋之中。你可以先生成一個多行注釋塊,然後在這個注釋塊之中再嵌套成第二個多行注釋。終止注釋時先插入第二個注釋塊的終止标記,然後再插入第一個注釋塊的終止标記:

/* 這是第一個多行注釋的開頭

/* 這是第二個被嵌套的多行注釋 */

這是第一個多行注釋的結尾 */

通過運用嵌套多行注釋,你可以快速友善的注釋掉一大段代碼,即使這段代碼之中已經含有了多行注釋塊。

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

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

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

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

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

在32位平台上,int和int32長度相同。

在64位平台上,int和int64長度相同。

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

swift 也提供了一個特殊的無符号類型uint,長度與目前平台的原生字長相同:

在32位平台上,uint和uint32長度相同。

在64位平台上,uint和uint64長度相同。

浮點數是有小數部分的數字,比如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,因為你給它賦的初始值看起來像一個整數:

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

當推測浮點數的類型時,swift 總是會選擇double而不是float。

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

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

整數字面量可以被寫作:

一個十進制數,沒有字首

一個二進制數,字首是0b

一個八進制數,字首是0o

一個十六進制數,字首是0x

下面的所有整數字面量的十進制值都是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:

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

通常來講,即使代碼中的整數常量和變量已知非負,也請使用int類型。總是使用預設的整數類型可以保證你的整數常量和變量可以直接被複用并且可以比對整數類字面量的類型推測。 隻有在必要的時候才使用其他整數類型,比如要處理外部的長度明确的資料或者為了優化性能、記憶體占用等等。使用顯式指定長度的類型可以及時發現值溢出并且可以暗示正在處理特殊資料。

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

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

要将一種數字類型轉換成另一種,你要用目前值來初始化一個期望類型的新數字,這個數字的類型就是你的目标類型。在下面的例子中,常量twothousand是uint16類型,然而常量one是uint8類型。它們不能直接相加,因為它們類型不同。是以要調用uint16(one)來建立一個新的uint16數字并用one的值來初始化,然後使用這個新數字來計算:

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

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

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

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

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

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

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

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

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

本例中,audiosample被定義為uint16的一個别名。因為它是别名,audiosample.min實際上是uint16.min,是以會給maxamplitudefound賦一個初值0。

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

orangesareorange和turnipsaredelicious的類型會被推測為bool,因為它們的初值是布爾字面量。就像之前提到的int和double一樣,如果你建立變量的時候給它們指派true或者false,那你不需要将常量或者變量聲明為bool類型。初始化常量或者變量的時候如果所賦的值類型已知,就可以觸發類型推測,這讓 swift 代碼更加簡潔并且可讀性更高。

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

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

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

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

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

下面這個例子中,(404, "not found")是一個描述 http 狀态碼(http status code)的元組。http 狀态碼是當你請求網頁的時候 web 伺服器傳回的一個特殊值。如果你請求的網頁不存在就會傳回一個404 not found狀态碼。

(404, "not found")元組把一個int值和一個string值組合起來表示 http 狀态碼的兩個部分:一個數字和一個人類可讀的描述。這個元組可以被描述為“一個類型為(int, string)的元組”。

你可以把任意順序的類型組合成一個元組,這個元組可以包含所有類型。隻要你想,你可以建立一個類型為(int, int, int)或者(string, bool)或者其他任何你想要的組合的元組。

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

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

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

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

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

作為函數傳回值時,元組非常有用。一個用來擷取網頁的函數可能會傳回一個(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:

因為toint方法可能會失敗,是以它傳回一個可選的(optional)int,而不是一個int。一個可選的int被寫作int?而不是int。問号暗示包含的值是可選,也就是說可能包含int值也可能不包含值。(不能包含其他任何值比如bool值或者string值。隻能是int或者什麼都沒有。)

你可以使用if語句來判斷一個可選是否包含值。如果可選有值,結果是true;如果沒有值,結果是false。

當你确定可選包确實含值之後,你可以在可選的名字後面加一個感歎号(!)來擷取值。這個驚歎号表示“我知道這個可選有值,請使用它。”這被稱為可選值的強制解析(forced unwrapping):

注意:使用!來擷取一個不存在的可選值會導緻運作時錯誤。使用!來強制解析值之前,一定要确定可選包含一個非nil的值。

像下面這樣在if語句中寫一個可選綁定:

你可以像上面這樣使用可選綁定來重寫possiblenumber這個例子:

這段代碼可以被了解為:“如果possiblenumber.toint傳回的可選int包含一個值,建立一個叫做actualnumber的新常量并将可選包含的值賦給它。”

如果轉換成功,actualnumber常量可以在if語句的第一個分支中使用。它已經被可選包含的值初始化過,是以不需要再使用!字尾來擷取它的值。在這個例子中,actualnumber隻被用來輸出轉換結果。

你可以在可選綁定中使用常量和變量。如果你想在if語句的第一個分支中操作actualnumber的值,你可以改成if var actualnumber,這樣可選包含的值就會被賦給一個變量而非常量。

你可以給可選變量指派為nil來表示它沒有值:

注意:nil不能用于非可選的常量和變量。如果你的代碼中有常量或者變量需要處理值缺失的情況,請把它們聲明成對應的可選類型。

如果你聲明一個可選常量或者變量但是沒有指派,它們會自動被設定為nil:

注意:swift 的nil和 objective-c 中的nil并不一樣。在 objective-c 中,nil是一個指向不存在對象的指針。在 swift 中,nil不是指針——它是一個确定的值,用來表示值缺失。任何類型的可選都可以被設定為nil,不隻是對象類型。

如上所述,可選暗示了常量或者變量可以“沒有值”。可選可以通過if語句來判斷是否有值,如果有值的話可以通過可選綁定來解析值。

有時候在程式架構中,第一次被指派之後,可以确定一個可選總會有值。在這種情況下,每次都要判斷和解析可選值是非常低效的,因為可以确定它總會有值。

這種類型的可選被定義為隐式解析可選(implicitly unwrapped optionals)。把想要用作可選的類型的後面的問号(string?)改成感歎号(string!)來聲明一個隐式解析可選。

一個隐式解析可選其實就是一個普通的可選,但是可以被當做非可選來使用,并不需要每次都使用解析來擷取可選值。下面的例子展示了可選string和隐式解析可選string之間的差別:

你可以把隐式解析可選當做一個可以自動解析的可選。你要做的隻是聲明的時候把感歎号放到類型的結尾,而不是每次取值的可選名字的結尾。

注意:如果你在隐式解析可選沒有值的時候嘗試取值,會觸發運作時錯誤。和你在沒有值的普通可選後面加一個驚歎号一樣。

你仍然可以把隐式解析可選當做普通可選來判斷它是否包含值:

你也可以在可選綁定中使用隐式解析可選來檢查并解析它的值:

注意:如果一個變量之後可能變成nil的話請不要使用隐式解析可選。如果你需要在變量的生命周期中判斷是否是nil的話,請使用普通可選類型。

繼續閱讀