- Swift 5從零到精通iOS開(kāi)發(fā)訓(xùn)練營(yíng)
- 張益琿編著
- 3010字
- 2022-07-27 18:32:06
2.4 兩種特殊的基本數(shù)據(jù)類型
Swift語(yǔ)言還支持兩種特殊的基本數(shù)據(jù)類型,分別是元組類型與可選值類型。元組在實(shí)際開(kāi)發(fā)中十分常用,開(kāi)發(fā)者使用元組可以創(chuàng)建出任意數(shù)據(jù)類型組合的自定義數(shù)據(jù)類型;而可選值類型是Swift語(yǔ)言的一大特點(diǎn),通過(guò)可選值類型,Swift語(yǔ)言對(duì)數(shù)值為空進(jìn)行了嚴(yán)格的把控。
2.4.1 元組
元組是Swift語(yǔ)言中重要的數(shù)據(jù)類型之一,元組允許一些并不相關(guān)的類型自由組合成為新的集合類型。Objective-C語(yǔ)言并不支持元組這樣的數(shù)據(jù)類型,這在很多時(shí)候會(huì)給開(kāi)發(fā)者帶來(lái)麻煩。類比生活中的一種情景,元組類型類似于日常生活中的套餐,現(xiàn)在各種服務(wù)業(yè)都推出了許多有特色的套餐供顧客選擇,方便為顧客提供一站式服務(wù)。元組提供的就是這樣一種編程結(jié)構(gòu),試想一下,編程中遇到這樣一種情形:一個(gè)商品有名字和價(jià)格,使用元組可以很好地對(duì)這種商品類型進(jìn)行模擬,示例如下:
//創(chuàng)建鋼筆元組類型,其中有兩種類型,即字符串類型的名稱和整數(shù)類型的價(jià)錢(qián) var pen:(name:String,price:Int) = ("鋼筆",2)
上面的代碼在創(chuàng)建元組類型的同時(shí)指定了其中參數(shù)的名稱,即名稱參數(shù)為name,價(jià)格參數(shù)為price,開(kāi)發(fā)者可以使用這些參數(shù)名稱來(lái)獲取元組中各個(gè)參數(shù)的值,示例如下:
//獲取pen變量名稱 var name = pen.name //獲取pen變量?jī)r(jià)格 var price = pen.price
開(kāi)發(fā)者在創(chuàng)建元組時(shí),也可以不指定元組中參數(shù)的名稱,元組會(huì)自動(dòng)為每個(gè)參數(shù)分配下標(biāo),下標(biāo)值將從0開(kāi)始依次遞增,示例如下:
//不指定參數(shù)名稱的元組 var car:(String,Int) = ("奔馳",2000000) //通過(guò)下標(biāo)來(lái)取得元組中各個(gè)組成元素的值 var carName = car.0 var carPrice = car.1
元組實(shí)例被創(chuàng)建后,開(kāi)發(fā)者也可以通過(guò)指定的變量或者常量來(lái)分解它,示例如下:
//不指定參數(shù)名稱的元組 var car:(String,Int) = ("奔馳",2000000) //進(jìn)行元組的分解 var (theName,thePrice) = car //此時(shí) theName變量被賦值為"奔馳",thePrice變量被賦值為2000000 print(theName,thePrice)
上面的代碼將元組實(shí)例car中的各個(gè)組成元素分解到具體變量,有一點(diǎn)讀者需要注意,分解后的變量必須與元組中的元素一一對(duì)應(yīng)(個(gè)數(shù)相等),否則編譯器就會(huì)報(bào)錯(cuò)。代碼中使用的print()函數(shù)為打印輸出函數(shù),print()函數(shù)可以接收多個(gè)參數(shù),將其以逗號(hào)分隔即可。有些時(shí)候,開(kāi)發(fā)者可能并不需要獲取某個(gè)元組實(shí)例中所有元素的值,這種情況下,開(kāi)發(fā)者也可以將某些不需要獲取的元素使用匿名的方式來(lái)接收,示例如下:
//不指定參數(shù)名稱的元組 var car:(String,Int) = ("奔馳",2000000) //進(jìn)行元組的分解,將Int型參數(shù)進(jìn)行匿名 var (theName,_) = car //此時(shí)theName變量被賦值為"奔馳" print(theName)
在Swift語(yǔ)言中,常常使用符號(hào)“_”來(lái)表示匿名的概念,因此“_”也被稱為匿名標(biāo)識(shí)符。上面的代碼實(shí)際上只分解出了元組car中的第一個(gè)元素(String類型)。
提示
元組雖然使用起來(lái)十分方便,但是其只適用于簡(jiǎn)單數(shù)據(jù)的組合,對(duì)于結(jié)構(gòu)復(fù)雜的數(shù)據(jù),要采用結(jié)構(gòu)體或者類來(lái)實(shí)現(xiàn)。
2.4.2 可選值類型
可選值類型(Optional類型)是Swift語(yǔ)言特有的一種類型。首先,Swift語(yǔ)言是一種十分強(qiáng)調(diào)類型安全的語(yǔ)言,開(kāi)發(fā)者在使用到某個(gè)變量時(shí),編譯器會(huì)盡最大可能保證此變量的類型和值的明確性,保證減少編程中的不可控因素。然而在實(shí)際編程中,任何類型的變量都會(huì)遇到值為空的情況,在Objective-C語(yǔ)言中并沒(méi)有機(jī)制來(lái)專門(mén)監(jiān)控和管理為空值的變量,程序的運(yùn)行安全性全部靠開(kāi)發(fā)者手動(dòng)控制。Swift語(yǔ)言提供了一種包裝的方式來(lái)對(duì)普通類型進(jìn)行Optional包裝,實(shí)現(xiàn)對(duì)空值情況的監(jiān)控。
在Swift語(yǔ)言中,如果使用了一個(gè)沒(méi)有賦值的變量,程序會(huì)直接報(bào)錯(cuò)并停止運(yùn)行。讀者可能會(huì)想,如果一個(gè)變量在聲明的時(shí)候沒(méi)有賦初值,在后面的程序運(yùn)行中就有可能被賦值,那么對(duì)于這種“先聲明后賦值”的應(yīng)用場(chǎng)景,我們應(yīng)該怎么做呢?在Objective-C中,這個(gè)問(wèn)題很好解決,只需要使用的時(shí)候判斷一下這個(gè)變量是否為nil即可。在Swift中是否也可以這樣做呢?使用如下代碼來(lái)進(jìn)行試驗(yàn):
var obj:String if obj==nil { }
編寫(xiě)上面的代碼后,可以看到Xcode工具依然拋出了一個(gè)錯(cuò)誤提示,其實(shí)在Swift語(yǔ)言中,未做初始化的普通類型是不允許使用的,哪怕是用來(lái)進(jìn)行判空處理也不被允許,當(dāng)然也就不可以與nil進(jìn)行比較運(yùn)算,這種機(jī)制極大地減小了代碼的不可控性。因此,開(kāi)發(fā)者在使用前必須保證變量被初始化,代碼如下:
var obj0:String obj0 = "HS" print(obj0)
但是上面的做法在實(shí)際開(kāi)發(fā)中并不常用,如果一個(gè)變量在邏輯上可能為nil,則開(kāi)發(fā)者需要將其包裝為Optional類型,改寫(xiě)上面的代碼如下:
var obj:String? if obj==nil { }
此時(shí)代碼就可以正常運(yùn)行了。分析上面的代碼,在聲明obj變量的時(shí)候,這里將其聲明成了String?類型,在普通類型后面添加符號(hào)“?”,即可將普通類型包裝為Optional類型。
Optional類型不會(huì)獨(dú)立存在,其總是附著于某個(gè)具體的數(shù)據(jù)類型之上,具體的數(shù)據(jù)類型可以是基本數(shù)據(jù)類型,可以是結(jié)構(gòu)體,也可以是類等。Optional類型只有兩種值,讀者可以將其理解為:
- 如果其附著類型對(duì)應(yīng)的量值有具體的值,則其為具體值的包裝。
- 如果其附著類型對(duì)應(yīng)的量值沒(méi)有具體的值,則其為nil。
舉一個(gè)例子,將Int類型的變量a進(jìn)行Optional包裝,此時(shí)a的類型為Int?,如果對(duì)a進(jìn)行了賦值,則可以通過(guò)拆包的方式獲取a的Int類型值,如果沒(méi)有對(duì)a進(jìn)行賦值,則a為nil。
提示
Optional類型中的nil讀者也可以理解為一種值,其表示空。
Optional類型是對(duì)普通類型的一種包裝,因此在使用的時(shí)候需要對(duì)其進(jìn)行拆包操作,拆包將使用到Swift中的操作符“!”。“?”與“!”這兩個(gè)操作符是很多Swift語(yǔ)言初學(xué)者的噩夢(mèng),如果讀者理解了Optional類型,那么對(duì)這兩個(gè)操作符的理解和使用將容易許多。首先需要注意,“?”符號(hào)可以出現(xiàn)在類型后面,也可以出現(xiàn)在實(shí)例后面,如果出現(xiàn)在類型后面,其代表的是此類型對(duì)應(yīng)的Optional類型,如果出現(xiàn)在實(shí)例后面,則代表的是可選鏈的調(diào)用,后面章節(jié)會(huì)詳細(xì)介紹。“!”符號(hào)同樣可以出現(xiàn)在類型后面與實(shí)例后面,它出現(xiàn)在類型后面代表的是一種隱式解析的語(yǔ)法結(jié)構(gòu),后面章節(jié)會(huì)介紹;出現(xiàn)在實(shí)例后面代表的是對(duì)Optional類型實(shí)例的拆包操作。示例如下:
//聲明obj為String?類型 var obj:String? = "HS" //進(jìn)行拆包操作 obj!
讀者需要注意,在使用“!”進(jìn)行Optional值的拆包操作時(shí),必須保證要拆包的值不為nil,否則程序運(yùn)行會(huì)出錯(cuò)。可以在拆包前使用if語(yǔ)句進(jìn)行安全判斷,示例如下:
//聲明obj為String?類型 var obj:String? = "HS" if obj != nil { obj! }
上面的代碼演示的編程結(jié)構(gòu)在實(shí)際應(yīng)用中十分廣泛,因此Swift語(yǔ)言還提供了一種if-let語(yǔ)法結(jié)構(gòu)來(lái)進(jìn)行Optional類型值的綁定操作,可以將上面的結(jié)構(gòu)改寫(xiě)如下:

上面的代碼可以這樣理解:如果obj有值,則if-let結(jié)構(gòu)將創(chuàng)建一個(gè)臨時(shí)常量tmp來(lái)接收obj拆包后的值,并且執(zhí)行if為真時(shí)所對(duì)應(yīng)的代碼塊,在執(zhí)行的代碼塊中,開(kāi)發(fā)者可以直接使用拆包后的obj值tmp。如果obj為nil,則會(huì)進(jìn)入if為假的代碼塊中,開(kāi)發(fā)者可以在else代碼塊中將obj重新賦值使用。這種if-let結(jié)構(gòu)實(shí)際上完成了判斷、拆包、綁定拆包后的值到臨時(shí)常量3個(gè)過(guò)程。
if-let結(jié)構(gòu)中也可以同時(shí)進(jìn)行多個(gè)Optional類型值的綁定,之間用逗號(hào)隔開(kāi),示例如下:

在同時(shí)進(jìn)行多個(gè)Optional類型值的綁定時(shí),只有所有Optional值都不為nil,綁定才會(huì)成功,代碼執(zhí)行才會(huì)進(jìn)入if為真的代碼塊中。如果開(kāi)發(fā)者需要在if語(yǔ)句的判斷中添加更多業(yè)務(wù)邏輯,可以通過(guò)追加子句的方式來(lái)實(shí)現(xiàn),示例如下:

上面的代碼在obj1不為nil、obj2不為nil并且obj1所對(duì)應(yīng)的拆包值小于obj2對(duì)應(yīng)的拆包值的時(shí)候才會(huì)進(jìn)入if為真的代碼塊中,即打印綁定的tmp1與tmp2的值。
你可能發(fā)現(xiàn)了,對(duì)于一個(gè)可選值類型的變量,每次使用時(shí)我們都需要為其進(jìn)行拆包操作,這相對(duì)會(huì)有些麻煩,其實(shí)Swift中還有一種語(yǔ)法:隱式解析。隱式解析適用于這樣的場(chǎng)景:當(dāng)我們明確某個(gè)變量初始時(shí)為nil,并且在之后使用之前一定會(huì)被賦值時(shí),我們可以將其聲明為隱式解析的可選值,再對(duì)這個(gè)變量進(jìn)行使用,就不需要進(jìn)行拆包操作了,例如下面的代碼會(huì)產(chǎn)生運(yùn)行錯(cuò)誤:
var obj4:Int? obj4 = 3 print(obj4 + 1) //會(huì)編譯異常,因?yàn)閛bj4沒(méi)有進(jìn)行拆包
如果將上面的代碼做如下的修改,就可以正常運(yùn)行了:
// 聲明obj4為隱式解析的變量 var obj4:Int! obj4 = 3 // 在使用時(shí),無(wú)須再進(jìn)行拆包操作,Swift會(huì)自動(dòng)幫我們拆包 print(obj4 + 1)
Optional值在Swift語(yǔ)言編程中的應(yīng)用十分靈活,在以后的編程練習(xí)中,讀者會(huì)逐步體會(huì)其中的奧妙。
- HTML5+CSS3+JavaScript從入門(mén)到精通:上冊(cè)(微課精編版·第2版)
- Designing Machine Learning Systems with Python
- Qt 5 and OpenCV 4 Computer Vision Projects
- TypeScript Blueprints
- Learning PostgreSQL
- Dynamics 365 Application Development
- Python Deep Learning
- 薛定宇教授大講堂(卷Ⅳ):MATLAB最優(yōu)化計(jì)算
- Mastering Scientific Computing with R
- Visual Basic程序設(shè)計(jì)習(xí)題解答與上機(jī)指導(dǎo)
- jQuery開(kāi)發(fā)基礎(chǔ)教程
- Julia高性能科學(xué)計(jì)算(第2版)
- Getting Started with Hazelcast(Second Edition)
- HTML5 APP開(kāi)發(fā)從入門(mén)到精通(微課精編版)
- Mastering Xamarin.Forms(Second Edition)