官术网_书友最值得收藏!

第2章 千里之行始于足下——Swift語言基礎

為了能夠使讀者更快地上手Swift編程。本章挑選了Swift語言的最基本特性加以介紹。盡管這些特性只占Swift全部特性的很少一部分,但卻是所有的Swift程序都必不可少的。所以,讀者通過對本章學習,可以使用Swift編寫最基本的程序,并對Swift提供的新特性深深地震撼。

本章要點

□ Swift中的分號

□ 變量和常量

□ 常用的數據類型

□ 字符和字符串的常用操作

□ 元組類型

□ 可選類型

□ 注釋

2.1 Swift語句和分號

通常來講,學習一種計算機語言會從Hello World開始。也就是在終端或窗口上輸出一行“Hello World”字符串,當然,輸出什么都可以,這只是為了練習而已。不過在編寫這行代碼之前,首先要了解這種編程語言的語句是怎樣寫的。例如,用Java的語句規則去寫Ruby代碼,很有可能會出錯。

Swift 語言編程格式總體來說中規中矩。不過,關鍵就在這個分號上。在 Java、C#這樣的靜態語言中,每條語句必須以分號(;)結尾。也就是說,在這些語言中,每條語句中的分號是可選的。但對于很多動態語言(如Ruby、Python等),如果每一條語句單獨占用一行,并不需要加分號,而只有多條語句寫在同一行時,才需要加分號。Swift語言吸取了動態語言的這個特性,將分號變成了可選的。例如,下面的 Swift語句都是合法的。

varid = 30

var product_var = "iPad5"; let xyz = 543.12;

id = 123;product_var = "iPhone7"

從這幾行代碼可以看出,如果在同一行寫多條語句,語句之間必須加分號。但多條語句的最后一條語句后面可以不加分號。如果一行只寫一條語句,可以不加分號,當然,也可以加分號。不過可能有很多程序員習慣了 C、C++、Java、C#等語言的寫法,總習慣在后面加分號。但這也無所謂,反正加一個分號也費不了多少事。

2.2 變量和常量

源代碼文件:src/ch02/var_let/var_let/main.swift

沒有變量,程序就像一灘死水,沒有活力。有了變量,程序才能千變萬化,豐富多彩。所以,在編寫大量Swift代碼之前,先來了解一下Swift是如何定義變量的。在某些情況下,只允許變量設置一次值,然后再也不允許修改了,這種特殊的變量被稱為常量。所以,在本節將著重介紹變量和常量。

2.2.1 定義和初始化

不管是什么語言,變量都必須確定數據類型,否則是沒法存儲數據。但不同的語言,獲取數據類型的方式是有區別的。例如,對于靜態語言(Java、C#等),必須在定義變量時指定其數據類型。當然,為了讓這個變量什么類型的值都能存儲,也可以將變量類型設為Object或相似的類型。但不管設為什么,類型是一定要指定一個的。所以,靜態語言變量的數據類型是在編譯時確定的。

對于動態語言,變量也必須要有一個數據類型,只是這個數據類型并不是在定義變量時指定的,而是在程序運行到為這變量第一次初始化的語句時才確定數據類型。所以,動態語言的變量數據類型是在程序運行時確定的,這也是為什么這種語言被稱為動態語言的原因之一。

不過在 Swift 語言中,使用了第三種方式來確定變量的數據類型,這就是“靜態定義,動態推導”。其中的“靜態定義”就是說變量的數據類型是在編譯時確定的。而“動態推導”則說明在定義變量時并不需要明確指定數據類型,而只需使用var定義變量即可,如果要定義常量,需要使用let。然后Swift編譯器在編譯代碼時,會根據變量(常量)初始化時右側的表達式推導當前變量(常量)的類型。要注意的是,這里的var和let與其他靜態語言中的 Object是不一樣的。var和 let最終是可以獲知準確類型的,而Object只是利用多態技術來存取各種數據類型的值,Object本身是不會反應具體類型的相應特性的(如屬性、方法等),除非進行強行轉換。例如,下面使用 var 定義了一個id變量。

var id = 20

這行語句是和下面的語句等效的,也就是說,編譯器最終會認為20是Int類型,所以,在編譯完程序后,會自動將id設為Int類型。所以id擁有Int類型的一切特征。

var id:Int = 20 // Int是數據類型,如何定義數據類型會在本節后面介紹

說道這里,就引出了變量定義的第一個需要注意的地方,就是如果不指定變量的數據類型,該變量必須被初始化。也就是說下面的語句是不合法的。

var id // 不合法,必須初始化

但是,如果為變量指定了一個數據類型,則可以在定義變量時不初始化,例如,下面的語句是合法的。

var id:Int

對于常量來說,不管指定不指定數據類型,都必須進行初始化。例如,下面兩條語句都是不合法的。

let const1   // 不合法,常量必須初始化

let const2:Int  // 不合法,常量必須初始化

而要想定義一個常量,必須使用下面的形式。

let const3:Int = 20 // 合法的常量定義(指定數據類型)

let const3 = 20  // 合法的常量定義(不指定數據類型,動態推導)

注意

不管是變量,還是常量。一旦確定了數據值類型,是不能后期改變的。例如,下面的代碼會拋出編譯錯誤。

var value = "abc"

value = 20

這里的value已經確定了是字符串(String)類型,不能再次被定義為Int類型。

除此之外還要注意,如果變量或常量在定義時未指定數據類型,初始化什么值都可以。一旦指定了數據類型,必須初始化與數據類型相符的值。例如,下面的代碼是錯誤的。

var value:String = 123 // 必須初始化字符串值

如果想使用一個var或let定義多個變量或常量,可以用逗號(,)分隔多個變量或常量。例如,下面定義的變量和常量都是合法的。

var v1 = "abc", v2:Float = 20.12,v3:Bool

let const1 = "xyz", const2:Double = 12.34;

注意

在大多數靜態語言中,指定整數或浮點數,會確認默認的類型。例如,在Java語言中,如果直接寫23,會認為23是int類型;如果要讓23變成long類型,則需要使用23L。如果直接寫23.12,編譯器會認為23.12是double類型,如果要將23.12變成float類型,需要使用23.12f。而對于float v = 23.12;,Java編譯器會認為是錯誤的,因為23.12是double,而不是float,正確的寫法是float v = 23.12f;。而對于short value = 23;是正確的。因為Java 編譯器會自動將23 轉換為short 類型,但23必須在short 類型的范圍內。這么做是因為在byte code 中byte、short、int 都是使用同一個指令,而float和double使用了不同的指令,所以浮點數沒有自動轉換(理論上是可以的,估計是某人比較懶,不想麻煩)。在Swift語言中,浮點數會自動轉換,所以var v:Float = 20.12是沒問題的。

在更深入介紹Swift語言之前,先拋出兩個全局函數:print和println。這兩個全局函數可以在任何地方使用。用于在終端輸出指定的信息(與C語言中的printf函數類似)。其中print輸出信息后不換行,要想換行,需要加上“\r\n”,而println函數在輸出信息后直接換行。之所以要先介紹這兩個函數,是因為在后面的章節會使用這兩個函數輸出用于演示 Swift 特性的信息。下面是使用這兩個函數的簡單形式。

var value = 34

let const1:String = "xyz"

println(value)

print(const1 + "\r\n")

在深入使用這兩個函數時再詳細介紹它們的使用方法。

2.2.2 將變量和常量值插入字符串中

在很多情況下,需要將多個變量的值連接在一起,并插入一些其他的字符串。如果這些變量都是字符串類型,可以直接使用加號(+)連接這些變量值。但如果這些變量不是字符串類型,就需要使用全局函數toString將它們轉換為字符串,然后才能使用加號連接。例如,下面代碼中定義了1個變量和兩個常量,分別為Int、String和Bool類型,現在要將這3個變量和常量的值進行連接,然后使用println函數輸出連接的結果。

var productId = 20

let productName:String = "iMac"

let available:Bool = true

println("Product ID:" + toString(productId) + " Product Name:" + productName + " Available:" +toString(available));

執行這段代碼后,會輸出如下的結果。

Product ID:20 Product Name:iMac Available:true

我們可以看到,盡管通過加號連接可以達到我們的目的,但卻使代碼變得不易維護和理解。在Swift中提供了一種更好的方法來達到這個目的,就是將變量和常量直接嵌入字符串,這樣會使代碼看起來更整潔。嵌入變量或常量的格式如下。

\(變量名/常量名)

下面的代碼使用這種嵌入變量/常量的方式重新實現了上面的需求。輸出結果與前面的代碼的輸出結果完全相同。

let description = "Product ID:\(productId) Product Name:\(productName) Available:\(available)"

println(description)

注意

經過測試,發現Swift語言的代碼在初始化變量或常量時,等號(=)兩側必須有空格,而且在使用加號(+)連接字符串時,兩側必須有空格,否則無法編譯通過。例如,var id=12是不合法的,需要使用var id = 12才行。也就是說“id”、“=”和“12”之間要有空格,當然,制表符也可以。有這個現在可能是Swift編譯器沒有考慮到這種情況,也許還有其他原因。不過添加這個現在是完全不符合邏輯的,大多數語言都沒有這個限制。也許當Swift正式版發布時會取消這個限制,大家在編寫Swift代碼時應注意這一點。

2.2.3 變量和常量的命名規則

由于Swift采用了Unicode 編碼,所以幾乎可以采用任何自己喜歡的字符作為變量(常量)名。例如,圖2-1所示的代碼使用了中文和特殊字符(笑臉)作為變量和常量名。

執行圖2-1所示的代碼后,會輸出如圖2-2所示的內容。

▲圖2-1 使用中文和笑臉作為變量名和常量名

▲圖2-2 輸出中文和笑臉變量的值

盡管 Swift 中的變量和常量名稱可以使用大多數的字符,但仍然有如下幾種字符不能包含在變量和常量名稱中,或不能作為變量和常量名稱。不能使用這些字符的原因主要是為了避免歧義。

□ 數學符號,例如,“+”、“-”、“*”、“/”等運算符號。

□ 箭頭。

□ 保留字,如var、let、for、if等。不能作為變量或常量名稱,但可以包含在變量和常量名稱中。

□ 非法的Unicode字符。

□ 連線和制表符。

如果一定要使用保留字作為變量或常量名的話,需要使用反引號(`)將保留字括起來。例如,下面的代碼使用了var作為變量名。

var 'var' = 3

println('var')

盡管使用保留字作為變量名和常量名是可行的,但并不建議這么做。

2.2.4 為變量和常量指定數據類型

盡管 Swift 語言支持類型推導,但如果想為變量或常量指定一個數據類型,也不是不可以的。在前面給出的Swift代碼中已經多次這么使用了。

Swift和C風格的語言(Java、C#、C++等)不同,需要在變量或常量的后面指定數據類型,而不是在前面。這一點和Pascal很像。變量(常量)和數據類型之間需要使用冒號(:)分隔,冒號兩側可以有空格(制表符),也可以沒有空格。例如,下面是幾行典型的為變量和常量指定數據類型的代碼。

var id:Int = 20

let productName : String = "Mac mini"

var price: Float = 4688

一旦為變量或常量指定了數據類型,在初始化變量或常量時,就只能指定與數據類型一致的值,Swift編譯器不會再進行類型推導。

2.3 數據類型

源代碼文件:src/ch02/data_type/data_type/main.swift

Swift語言也和其他語言一樣,提供了若干個數據類型可供我們使用。除了幾乎任何語言都支持的整數類型、浮點類型、布爾類型、字符串類型等,還指出一些特殊的類型,如元組類型、可選類型。不管是什么數據類型,在 Swift 語言中,數據類型名稱都是以大寫字母開頭,并不存在像Java一樣的int、float等內嵌的數據類型。在本節將詳細介紹這些數據類型的使用方法。

2.3.1 整數類型

整型是編程語言中最常用的數據類型。在Swift語言中支持8、16、32、64位的整型。這4類整型的類型名稱如下。

□ 8位整型:Int8。

□ 16位整型:Int16。

□ 32位整型:Int32。

□ 64位整型:Int64。

在Swift語言中不同的整型擁有不同的類型別名(會在后面詳細介紹),這些類型別名如下。

□ Byte:8位整型(UInt8)。

□ SignedByte:8位整型(Int8)。

□ ShortFixed:16位整型(Int16)。

□ Int:32位整型(Int32)。

□ Fixed:32位整型(Int32)。

在實際使用中,可以使用這些類型別名代替相應的整型。例如,下面是使用這些類型和類型別名定義的一些變量和常量。

var value1:Byte = 20

var value2:SignedByte = 30

var value3:ShortFixed = 1234

let value4:Int = 200

let value5:Fixed = 12345

var value6:Int64 = 4433113567

注意

在初始化不同的整型時要注意整型的取值范圍。例如,SignedByte 的取值范圍是?128 至 127。如果超過了這個取值范圍,將無法成功編譯程序。例如,var value:Byte = 1234是不合法的。

Swift還提供了另外一套整型,這就是無符號類型。與前面相應的有符號整型對應的無符號整型如下。

□ 8位無符號整型:UInt8。

□ 16位無符號整型:UInt16。

□ 32位無符號整型:UInt32。

□ 64位無符號整型:UInt64。

關于無符號整型應該了解如下幾點。

□ 無符號整型除了UInt外,并未定義其他的類型別名。也就是說,并沒有像UByte這樣的數據類型(至少目前沒有)。

□ 無符號整型的最小值是0,不允許設置負數;否則無法成功編譯。

每一個有符號整型和無符號整型都有其取值范圍,也就是最大值和最小值。例如,Int8的取值范圍是?128~127,UInt8的取值范圍是0~255。對于取值范圍更大的整型,我們也沒有必要記。因為每一個整型都有min和max屬性,用于獲取當前類型的最大值和最小值。例如,下面的代碼可以分別獲取Int32的最小值和最大值。

let minIntValue = Int32.min;

let maxIntValue = Int32.max;

除此之外,在 Swift 語言中還定義了很多內置的變量,用于獲取數值類型的最大值和最小值。例如,INT16_MAX用于獲取Int16的最大值,INT16_MIN用于獲取Int16的最小值。但有一些數值類型的這些變量并沒有定義,估計是因為 Swift 語言目前還是測試版的原因,可能Swift正式版出來后會好一些。

注意

對于Int 類型比較特殊,該類型會隨著當前OS X 系統支持的位數不同而不同。例如,如果在32位的OS X系統中,Int = Int32;如果在64位的OS X系統中,Int =Int64。

2.3.2 數制轉換

Swift語言中的類型可以表示為十進制、二進制、八進制和十六進制。默認是十進制,數值前面加“0b”為二進制,數值前加“0o”位八進制,數值前加“0x”為十六進制。例如,下面的幾個常量分別用十進制、二進制、八進制和十六進制的數值進行了初始化,并輸出了這些常量值。

let decimalInt = 20

let binaryInt = 0b1100 //相當于十進制的12

let octalInt = 0o21  // 相當于十進制的17

let hexInt = 0x11   //相當于十進制的17

println(binaryInt);

println(octalInt);

println(hexInt);

這段代碼的輸出結果如下。

12

17

17

從這一點可以看出,盡管初始化時使用的是二進制表示法,但仍然以十進制數值表示常量值。

2.3.3 浮點類型

常用的浮點數分為單精度和雙精度浮點數,數據類型名稱分別是Float和Double。其中Double也可以用Float64代替。下面是一些聲明為浮點類型的變量和常量。

var value1:Float = 30.12

var value2:Float64 = 12345.54

let value3:Double = 332211.45

2.3.4 數值的可讀性

為了增強較大數值的可讀性,Swift語言增加了下劃線(_)來分隔數值中的數值。例如,如果看到1000000000,估計很少有人會立刻反映出是10億。大多數人可能需要查0的個數來判斷該數值的大小。但使用 1_000_000_000,大多數人(尤其是搞財務的)一眼就可以看出是10億。

不管是整數,還是浮點數,都可以使用下劃線來分割數字。例如,下面是幾個使用下劃線分隔的數值初始化的變量和常量。

let value1 = 12_000_000

let value2 = 1_000_000.000_000_1

var value3:Int = 1_00_000

要注意的是,下劃線兩側的數字不一定是3個為一組。分隔一個或n個數字都可以,例如,1_0_0_0_0_1也是合法的數字,不過這樣分隔就沒意義了。

2.3.5 數值類型之間的轉換

數值轉換分為如下幾種形式。

□ 整數之間的轉換。

□ 浮點數之間的轉換。

□ 整數和浮點數之間的轉換。

對于整數之間的轉換,如果之間使用數值位常量或變量賦值,則會自動轉換,當然,前提是數值不超過整型的取值范圍。

var value1:Byte = 12

let value2:Int32 = 12

在這兩行代碼中,同樣都是12。但Swift編譯器會將第一個12看做是Byte類型的值,而將第二個12看做是Int32類型的值。

如果是一個整型變量(常量)為另一個整型變量(常量)賦值,則需要強行轉換。即使將Byte變量值賦給Int變量值也需要強行轉換 其實這個可以做得更人性一點,也就是說將一個變量或常量賦給另外一個取值范圍更大的變量或常量時,應該自動完成轉換。

var int_value1:Int = 100

var byte_value:Byte = Byte(int_value1)

var int_value2:Int = Int(byte_value)

從這幾行代碼可以看出,強行轉換的語法格式如下。

類型名 (變量/常量名)

浮點數之間以及浮點數和整數之間的轉換與整數之間的轉換類似,同樣需要類型強行轉換。

var float_value:Float = 1.23

var double_value1:Double = 1.23

var double_value2:Double = Double(float_value)

var int_value:Int = Int(double_value1)

同樣是1.23,第一個1.23被認為是Float類型,第二個1.23被認為是Double類型。而將float_value賦給double_value2時仍然需要類型的強行轉換。

將浮點數轉換為整數時,會采用舍去的方式。例如,1.23和1.99被轉換為整數后的結果都是1。

2.3.6 類型別名

Swift中的類型別名和C/C++中的typedef類似,就是為一個類型起一個更有意義的別名。例如,在前面已經介紹過多個類型別名,如Byte、SignedByte等。只是typedef和C/C++中定義變量的規則一樣,類型寫在前面,自定義的類型名寫中后面。代碼如下:

typedef int mytype; // C/C++中的類型定義,mytype是新類型

如果在Swift中定義類型別名(新類型),需要用到typealias關鍵字。typealias的語法格式如下。

typealias 類型別名 = 原始類型

下面的代碼就是一個典型的類型別名的例子。其中NewType就是Int32的類型別名。也就是說,在定義變量或常量時,NewType和Int32是完全一樣的。

typealias NewType = Int32

var new_value:NewType = 123

2.3.7 布爾類型

布爾類型是Bool,用于進行邏輯判斷。例如,if語句就是布爾類型最常用的地方。下面的代碼定義了一個布爾類型的變量,然后通過if語句進行判斷,如果布爾類型變量值為true,則會執行if語句中的部分,否則會執行else語句中的部分。

var isFile:Bool = true

if isFile

{

println("isFile is true");

}

如果改用布爾類型的地方用了其他數據類型,那么將會編譯出錯。例如,下面的if語句就無法編譯通過。

let i = 20

if i     // 無法編譯通過,i不是Bool類型,是Int類型

{

println("i = \(i)");

}

正確的寫法應該將 if后面的部分改成Bool類型的值,具體代碼如下。

let i = 20

if i == 20   // i = 20的結果是Bool類型,所以可以成功編譯

{

println("i = \(i)");

}

2.4 字符和字符串

源代碼文件:src/ch02/char_string/char_string/main.swift

字符和字符串也是 Swift 語言中的兩個重要類型,只是由于這兩個數據類型較復雜,所以單獨用一節詳細討論。

2.4.1 字符類型的常量和變量

字符類型的值只能存儲一個字符(Unicode字符),使用Character表示字符類型。Swift語言中的字符類型與大多數語言中的字符表示法不同。例如,在Java中,字符需要使用單引號(')括起來,而在Swift語言中,字符和字符串都要使用雙引號(")括起來。

let charValue1:Character = "a"

var charValue2:Character = "上"

使用字符類型時應了解如下兩點。

□ 由于字符和字符串都使用雙引號,所以,要想將變量或常量定義為字符類型,必須指定Character。如果不指定任何類型,并且直接使用值進行初始化。Swift編譯器會認為用雙引號括起來的是字符串,而不是字符。當然,如果右側是一個返回 Character 的函數或方法,仍然會認為左側的變量或常量是 Character 類型的值。

□ 雖然字符和字符串都使用雙引號。但如果將變量或常量聲明為 Character,雙引號括起來的部分只能是一個字符,0個字符和大于1個字符都不可以,否則Swift編譯器會報錯。

2.4.2 字符串類型的常量和變量

字符串類型是 String。如果在定義變量或常量時,不指定類型。系統會認為用雙引號括起來的部分是字符串。下面是幾個String類型的常量和變量的定義及初始化代碼。

var strValue1:String = "abcd"

let strValue2 : String = "變形金剛5"

如果要初始化一個空串(長度為 0 的字符串),可以直接使用(""),也可以使用 String對象(構造方法沒有參數值)。如果想為字符串設置值,也可以用String對象,只需要在String的構造方法中傳入要初始化的字符串即可。

var emptyString1 = ""   // 初始化一個空的字符串變量

var emptyString2 = String(); // 初始化一個空的字符串變量

var str1 = "abc"

var str2 = String("abc")

2.4.3 枚舉字符串中的所有字符

字符串是由字符組成的,也就是說,字符串是字符的集合。那么也就可以用枚舉集合中元素的方法來枚舉字符串中的字符。所以,可以使用下面的for循環來枚舉charCollection中的所有字符。

let charCollection = "獲取字符串中的每一個字符"

for c in charCollection

{

print("<" + c + ">")

}

執行這段代碼后,會輸出如下的內容。

<獲><取><字><符><串><中><的><每><一><個><字><符>

2.4.4 獲取字符串中字符的Unicode編碼

由于在 Swift語言中每一個字符都使用了Unicode編碼,所以,也可以獲取字符串中每一個字符的Unicode編碼。

String類有一個unicodeScalars屬性,用于獲取字符串中字符的Unicode集合,可以使用下面的代碼獲取一個字符串中的所有字符的Unicode。

let strValue3 = "abcd上下左右"

for c in strValue3.unicodeScalars

{

print("\(c.value) ")

}

執行這段代碼后,會輸出如下的內容。

97 98 99 100 19978 19979 24038 21491

從輸出結果可以看出,前4個字符由于是標準的ASCII,所以輸出的Unicode值都小于255,而后面4個字符是漢字(占用雙字節),所以輸出的Unicode值都很大。

2.4.5 字符串和字符的連接

不僅字符串和字符串之間可以使用加號(+)進行連接,字符串和字符之間也可以使用。例如,下面的代碼連接了一個字符和一個字符串,并輸出了連接結果。

let strValue4 = "abcd"

let charValue3:Character = "e"

let strValue5 = strValue4 + charValue3

println(strValue5);

輸出結果如下:

abcde

2.4.6 在字符串中包含特殊字符

有時需要在字符串中包含特殊字符。這些特殊字符主要分如下兩種情況。

□ 會引起歧義的字符,如雙引號、單引號。

□ 不好輸入的字符,例如,一個心形字符。

對于第一種情況,直接使用轉義符即可。例如,下面的代碼在字符串中包含了單引號和雙引號,這兩個特殊符號使用反斜杠(\)進行轉義。

let strValue6 = "\"今天好熱,不想出去,不想上班,只想\'睡覺\'\""

println(strValue6);

執行這段代碼后,輸出的結果如下。

“今天好熱,不想出去,不想上班,只想'睡覺'”

下面是比較常用的使用轉義符輸出的字符。

□ \0:null字符。

□ \\:反斜杠。

□ \t:制表符。

□ \n:新行符號。

□ \r:回車符。

□ \":雙引號。

□ \':單引號。

如果要在字符串中包含第二類特殊字符,需要使用十六進制表示的Unicode編碼。該編碼分為1個字節、兩個字節和4個字節表示法。分別用“\xnn”、“\unnnn”和“\Uxnnnnnnnn”表示。其中n表示十六進制。下面的代碼分別用這3種Unicode表示法輸出不同的特殊字符。

let strValue7 = "\x41"   // A

println(strValue7)

let strValue8 = "\u2600"  // ?

println(strValue8)

// 4字節Unicode字符,使用\Unnnnnnnn

let strValue9 = "\U0001F496" //心形字符

println(strValue9)

2.4.7 字符串之間的比較

Swift中的字符串之間的比較很簡單。不管參與比較的雙方是值,還是變量,只需直接使用“==”,“<”和“>”比較即可。

var strValueA = "abcd"

var strValueB = "abce"

if strValueA > strValueB

{

println("strValueA > strValueB");

}

else if strValueA < strValueB

{

println("strValueA < strValueB");

}

else

{

println("strValueA = strValueB");

}

2.4.8 字符串的大小寫轉換

使用String的兩個屬性(uppercaseString和lowecaseString),可以將字符串中的26個英文字母從小寫轉換為大寫,或從大寫轉換為小寫。

let lowercaseStr = "abcdefg"

// 從小寫轉換為大寫

let uppercaseStr = lowercaseStr.uppercaseString

println(uppercaseStr);

// 從大寫轉換為小寫

println(uppercaseStr.lowercaseString)

2.5 元組(tuples)類型

源代碼文件:src/ch02/tuples/tuples/main.swift

元組類型是Swift語言提供的一種新數據類型,英文名字是tuples。盡管元組類型是新的,但其表現形式和其他類型(如結構體,數組)還有一些類似。元組,說白了,就是可以包含多個值的數據類型。

2.5.1 元組類型的定義

元組類型沒有像那些簡單類型(如 String、Int)一樣有類型名,不過如果初始化時指定了元組值,Swift編譯器會自動推導出該變量或常量是元組類型。元組類型變量(常量)在初始化時使用一對圓括號將元組中的值括起來。例如,下面的代碼定義了一個元組類型常量,并輸出了這個常量值。

let product1 = (20, "iPhone6", 5888)

println(product1)

當執行這兩行代碼時,會輸出如下的結果。

(20, iPhone6, 5888)

很明顯,product1表示的元組類型常量包含了3個值,其中20是Int類型的值,“iPhone6”是String類型的值,5888是Int類型的值。

2.5.2 獲取元組中的元素值

既然元組類型可以存儲多個值,那么就面臨一個問題,如何獲取元組中某個元素的值呢?其實很簡單,只需要將元組類型中每一個元素的值分別賦給不同的變量或常量即可。賦值的方法是用圓括號定義多個變量或常量,然后使用元組類型值在右側賦值,具體代碼如下:

let product1 = (20, "iPhone6", 5888);

var (id, name, price) = product1;// 分別將product1中的3個值賦給3個變量(id,name,price)

// 分別輸出product1中的3個值

println("id=\(id) name=\(name) price=\(price)");

如果我們只想獲取元組類型值中的一個或幾個值,并不想全部獲取這些值,那么對那些不打算獲取值的元組元素,可以使用下劃線(_)占位。例如,下面的代碼只獲取了product1的第二個元素值,也就是name,其他的位置都使用下劃線替代(不需要定義變量或常量)。

let (_,name1,_) = product1

println("name1=\(name1)")

2.5.3 為元組中的元素命名

其實,從元組類型值中獲取其元素的值還有一個更簡單的方法,就是為每一個元素命名,引用的方法和引用對象屬性相同。例如,下面的代碼為product3中的3個元素命名,并且輸出了其中的name元素值。

let product3 = (30, name:"iPhone8", price:5988)

println(product3.name)

如果嫌麻煩,可以只為需要單獨獲取值的元素命名,那些不需要通過直接引用方式獲取值的元素可以不為其命名。

2.6 可選類型

可選類型也是 Swift 語言新添加的對象。主要是為了解決對象變量或常量為空的情況。在前面定義的變量和常量都不能為空。里面必須要有值。

Swift中的可選類型則允許變量(常量)中沒有值(被設為nil)。要注意的是,Swift中的nil和Objective-C中的nil不一樣。前者的nil表示沒有值,而后者的nil表示變量值為空。

可選類型需要在類型后面加一個問號(?)。一個典型的例子是String類有一個toInt方法,該方法會將字符串轉換為 Int 類型。不過這里就有一個問題,字符串中可能包含非數字的字符,這時就會轉換失敗。如果在其他語言中,不添加錯誤捕捉,可能會拋出異常,而在Swift中,如果轉換失敗,就直接返回nil。表示沒有返回Int類型的值(反正你想加捕捉異常做不到,因為Swift中壓根就沒有異常捕捉)。這里的toInt方法返回的就是一個可選類型。

下面的代碼將numStr中的值轉換為Int類型的值,并輸出該值。

var numStr:String = "123"

var value:Int? = numStr.toInt(); // value必須定義為可選的Int類型,否則無法成功編譯

println(value)

如果將123改成會導致轉換失敗的值,如a123,那么執行上面的代碼后就會輸出nil了。

對于一個可選類型的變量或常量,通常在使用之前需要進行判斷,例如,下面的代碼會對value進行判斷,如果確實轉換成功(不為nil),則輸出一行文本。

if value != nil

{

println("轉換成功")

}

不過每次使用value變量時都進行判斷很麻煩,所以,Swift添加了一個用于確定可選類型變量一定有值的感嘆號(!)。當對value第一次判斷后,如果能確認該變量已經被賦了值,后面就可以直接在value后加感嘆號使用該變量了。

println(value!)

如果在可選類型變量(常量)后面加感嘆號,當變量(常量)為 nil 時,程序會中斷,并在終端輸出如下的信息。

fatal error: unexpectedly found nil while unwrapping an Optional value

所以在可選變量(常量)后面加感嘆號時,要確保該變量(常量)中一定有值。

現在已經知道了,在引用可選類型變量(常量)時,后面加感嘆號是為了在該變量(常量)中沒有值(為nil)時拋出運行時異常。那么每次都加感嘆號也挺麻煩,所以干脆在定義可選類型變量(常量)時將問號改成感嘆號,這樣就可以直接引用這些可選類型變量和常量了。

var numStr:String = "123"

var value:Int! = numStr.toInt(); // value必須定義為可選的Int類型,否則無法成功編譯

// 即使value后面不加!(當然,加!也沒問題),當value為nil時以后拋出異常

println(value)

注意

在使用可選類型變量(常量)時,如果使用問號(?)來定義,并且單獨使用這些變量和常量,后面是可以不加感嘆號(!)的。但要讓這些變量和常量和其他的值通過操作符進行操作,那就必須要加感嘆號了。如下面的代碼是合法的。

var numStr:String = "123"

var value:Int! = numStr.toInt();

println(value) // 如果value為nil,則會輸出nil

但下面的代碼就無法成功編譯了。

var numStr:String = "123"

var value:Int! = numStr.toInt();

println(value + 4)// 編譯失敗,value必須寫成value!,或在定義value時使用“!”

2.7 注釋

Swift和C++的注釋幾乎是相同的,也支持單行注釋(用“//”進行注釋)和多行注釋(用“/* ... */進行注釋)。不過Swift對其做了擴展。在多行注釋中可以嵌套多行注釋。例如,下面的注釋在Swift語言中是合法的。

/* 上層的多行注釋

/* 嵌套的

多行注釋

*/

*/

2.8 小結

本章所介紹的關于Swift的知識是Swift語言最基礎的部分。希望讀者認真閱讀本章的內容。因為在后面的章節將會大量涉及本章講的內容,如果讀者對這些內容不了解,閱讀Swift源代碼會有很大困難。

主站蜘蛛池模板: 凌海市| 通城县| 兰西县| 肇东市| 临江市| 祥云县| 昌宁县| 浦东新区| 札达县| 青浦区| 微山县| 监利县| 贵州省| 商洛市| 巴青县| 巩义市| 遂川县| 光泽县| 梁平县| 兴文县| 馆陶县| 青浦区| 定安县| 许昌县| 云阳县| 平凉市| 礼泉县| 万源市| 涞水县| 阜新市| 宁明县| 黔西| 望江县| 丽水市| 怀远县| 苍南县| 汉寿县| 永清县| 神池县| 北票市| 桂东县|