- Swift權(quán)威指南
- 李寧編著
- 1636字
- 2019-01-02 10:22:11
第3章 萬丈高樓平地起——基本操作符
操作符是任何計(jì)算機(jī)語言的最核心部分之一。例如,四則運(yùn)算、求余、邏輯運(yùn)算對于程序都是非常重要的。在Swift語言中,除了支持常規(guī)的操作符外(任何語言都支持的操作符),還新增加了很多操作符,以及對部分常規(guī)操作符進(jìn)行了擴(kuò)展(如求余支持浮點(diǎn)數(shù))。本章將詳細(xì)介紹 Swift 支持的最基本,也是最常用的操作符。更復(fù)雜的操作符會在后面的章節(jié)詳細(xì)討論。
本章要點(diǎn)
□ Swift語言支持哪些操作符
□ 賦值操作符
□ 數(shù)組操作符
□ 復(fù)合賦值操作符
□ 比較操作符
□ 三元條件操作符
□ 區(qū)間操作符
□ 邏輯操作符
3.1 操作符的種類
操作符(Operator,或稱為運(yùn)算符)是所有語言的必需品,Swift也不例外。通常操作符需要和操作數(shù)一同出現(xiàn)。根據(jù)操作數(shù)的個(gè)數(shù),可以分為一元、二元和三元操作符。這里的“元”就是指操作數(shù)。
□ 一元操作符:只有一個(gè)操作數(shù)。例如,符號(?)、自加 (++)、自減(??)都屬于一元操作符。一元操作符又分為前置和后置一元操作符。這里的前置和后置是指操作符相對于操作數(shù)的位置。例如,-a中的“-”就是前置操作符,而a++中的“++”就屬于后置操作符。
□ 二元操作符:這類操作符是最常用的,絕大多數(shù)操作符都屬于這類操作符。例如,最常用的加(+)、減( ?)、乘(*)、除(/)就屬于二元操作符。二元操作符是中置的,也就是說,操作符會出現(xiàn)中兩個(gè)操作數(shù)之間,例如a + b。
□ 三元操作符:這類操作符可能并不多見。在Swift語言中只有一個(gè)三元操作符,就是三元條件操作符:a?b:c。其中a、b、c是操作數(shù),夾在它們之間(“?”和“:”)的是操作符。
3.2 賦值操作符
賦值操作(a = b)表示用b的值來初始化或更新a的值,例如,下面是一些標(biāo)準(zhǔn)的賦值操作。
var a = 10
let b = a
b = 10
a = b
如果等號(=)右側(cè)是一個(gè)元組類型的值,那么等號左側(cè)也必須是一個(gè)元組形式的變量或常量。而且在賦值的過程中,右側(cè)元組值中每一個(gè)分量值會被分別賦給左側(cè)對應(yīng)的變量或常量。
var (x, y, z) = (1,2,3)
// 現(xiàn)在 x 等于 1, y 等于 2
要注意的是,在C語言和Objective-C中,需要Bool值的地方也可以使用整數(shù)值代替,0表示false,非0表示true。所以下面的代碼在C或Objective-C中是正確的。
int x = 20
int y = 100
if(x = y) // 可以滿足條件
{
... ...
}
對于 Swift語言來說,賦值語句是不返回值的,所以下面的代碼在 Swift語言中是錯(cuò)誤的。
var x = 20
var y = 100
if x = y
{
// 無法編譯通過,因?yàn)閤 = y不會返回任何值
}
Swift的這個(gè)特性使你無法將等于操作符(==)錯(cuò)寫成賦值操作符(=)。盡管像Java這樣的語言可以在一定程度上避免這種錯(cuò)誤(因?yàn)樵贘ava中不能用整數(shù)代替Bool類型值),但如果賦值的變量正好是一個(gè)布爾類型,那么仍然可能錯(cuò)將(==)錯(cuò)寫成(=)。
3.3 數(shù)值操作符
Swift 語言支持標(biāo)準(zhǔn)的四則運(yùn)算操作符,其他數(shù)值操作符還包括整數(shù)求余、浮點(diǎn)數(shù)求余、自增、自減、一元負(fù)號、一元正號操作符。本節(jié)將介紹這些操作符的基本使用方法。
3.3.1 四則運(yùn)算操作符
Swift 中所有數(shù)值類型都支持基本的四則運(yùn)算。
□ 加法(+)。
□ 減法(?)。
□ 乘法(*)。
□ 除法(/)。
例如,下面是一些數(shù)值進(jìn)行基本運(yùn)算的例子。
letx= 1+ 2 // x= 3
var y= 5 -3 // y= 2
var abc= 2*3 // abc =6
var c= 10.0 /2.5 // c= 4.0
與 C 語言、Objective-C、Java等語言不同,Swift的數(shù)值默認(rèn)是不允許溢出的。例如,下面的代碼是無法編譯通過的。
let x:Byte = 1234 // 1234超出了Byte的取值范圍
var y:Byte = 12*33 // Swift編譯器在編譯時(shí)會計(jì)算12*33的值,很明顯,它們的乘積超出了Byte的范圍
如果在計(jì)算數(shù)值時(shí)使用的變量、常量或方法(函數(shù))返回的值,即使數(shù)值超出范圍,也是可以編譯通過的,但執(zhí)行時(shí)會拋出異常,也就是說溢出會變成一個(gè)運(yùn)行時(shí)錯(cuò)誤。例如,下面的代碼在運(yùn)行時(shí)程序會中斷。
let x:Byte = 120
var y:Byte = 20 * x // 執(zhí)行這條語句會拋出異常
如果需要考慮到溢出的情況,可以使用溢出操作符進(jìn)行運(yùn)算,例如,a &* b。即使 a和b的乘積超出了數(shù)值類型的取值范圍,也會輸出溢出的結(jié)果。由于Swift中的一些高級操作符涉及現(xiàn)在還沒講過的概念,所以這些高級操作符(包括溢出操作符)將放到本書的后面講解。
加法(+)運(yùn)算符不僅能用于數(shù)值的相加,也能用于字符和字符、字符和字符串以及字符串和字符串之間的連接。這3種情況下連接的結(jié)果都是字符串。
let c1:Character = "a"
let c2:Character = "b"
var s1:String = c1 + c2 // s1 = "ab"
var s2:String = c1 + s1 // s2 = "aab"
var s3:String = s1 + s2 // s3 = "abaab"
3.3.2 整數(shù)求余
整數(shù)求余(a%b)就是指計(jì)算a最多可以容納多少個(gè)b,最后多出來那部分就是余數(shù)。例如,9 % 4 = 1,這里1就是余數(shù)。也就是說,9最多容納2個(gè)4,那么剩余的那個(gè)1就是余數(shù)。
要注意的是,求余操作符(%)在其他語言中又可以稱為取模運(yùn)算。不過實(shí)際上,%可以對負(fù)數(shù)進(jìn)行操作,所以“求余”比“取模”可能更合適些。
如果要為求余操作符給出一個(gè)計(jì)算公式的話,那么這個(gè)公式如下。
a = (b ×倍數(shù)) + 余數(shù)
這個(gè)公式也可以是。
余數(shù) = a - (b ×倍數(shù))
如果對負(fù)數(shù)使用%,那么計(jì)算結(jié)果也是負(fù)數(shù)。例如,?9 % 4 = ?1,如果將這個(gè)表達(dá)式帶入公式,結(jié)果就是。
-9 = ( 4 × -2) + -1
所以余數(shù)是?1。
注意
如果%后面的操作數(shù)(也就是b)為負(fù)數(shù),那么這個(gè)負(fù)號將被忽略。也就是說 a % b = a % (-b)。另外,%后面的操作數(shù)如果加負(fù)號,要用圓括號括起來。
3.3.3 浮點(diǎn)數(shù)求余
與其他語言不同,Swift是可以對浮點(diǎn)數(shù)求余的。例如,8.5 % 2.5 = 1.0。浮點(diǎn)數(shù)求余也可以使用整數(shù)求余的公式。如果將這個(gè)表達(dá)式代入公式的結(jié)果是。
8.5 = (2.5 × 3) + 1.0
3.3.4 自增和自減
和C語言一樣,Swift也提供了使變量增1和減1的操作符。自增使用兩個(gè)加號(++),自減使用兩個(gè)減號(??)。不過和C語言不同的是操作數(shù)可以是整數(shù),也可以是浮點(diǎn)數(shù)。
和C語言一樣,Swift 也提供了方便對變量本身加1或減1的自增(++)和自減(??)的運(yùn)算符。其操作對象可以是整形和浮點(diǎn)型。
自增和自減還分為前自增、后自增;前自減、后自減。這里的前和后是指自增和自減操作符相對于操作數(shù)的位置。前自增和前自減操作符位于操作數(shù)前面,例如,++a、??b。后自增和后自減操作符位于操作數(shù)后面,例如,a++、b??。它們的區(qū)別是當(dāng)操作符位于操作數(shù)前面時(shí),先自加或自減,然后再返回變量值。當(dāng)操作符位于操作數(shù)后面時(shí),先返回變量值,然后再自加或自減。
var i = 1
var v = ++i // v = 2
var m = v++ // m = 2
var x = 2.5
x = ++x // x = 3.5
x = x++ // x = 3.5
盡管單獨(dú)增加和減少變量值時(shí)使用++a、a++、??a和a??都可以。但推薦使用++a和??a,因?yàn)樵诜祷刈兞恐抵跋仍?或減1更符合邏輯。
3.3.5 一元負(fù)號和正號
數(shù)值的正負(fù)號可以使用前綴?(即一元負(fù)號)來切換。
let three= 3
letminusThree= -three // minusThree等于 ?3
letplusThree= -minusThree // plusThree等于 3
要注意的是一元負(fù)號(?)需要寫在操作數(shù)之前,與操作數(shù)之間沒有空格。
一元正號(+)不做任何改變地返回操作數(shù)的值。使用規(guī)則與一元負(fù)號相同。盡管一元正好做的是無用功,但當(dāng)使用一元負(fù)號表示一個(gè)負(fù)數(shù)時(shí),使用一元正號表示正數(shù)會使你的代碼更容易閱讀,當(dāng)然,對于某些審美能力很強(qiáng)的人來說,會看出代碼之美。
3.4 復(fù)合賦值操作符
復(fù)合賦值(Compound Assignment)就是指將其他操作符和賦值操作符組合在一起使用,例如+=、?=都屬于復(fù)合賦值操作?;旧蠈儆贑風(fēng)格的語言(Java、C#、C++等)都支持這類操作符。
我們也可以將復(fù)合賦值操作符看著是兩個(gè)操作數(shù)進(jìn)行運(yùn)算并賦值的簡寫形式,例如,a += b相當(dāng)于a = a + b。
var a = 1
a += 2 //相當(dāng)于a = a + 2,所以a等于 3
注意
符合賦值運(yùn)算沒有返回值,也就是說,let b = a += 2 是錯(cuò)誤的寫法。
3.5 比較操作符
所有在標(biāo)準(zhǔn)C語言中的比較運(yùn)算都可以在Swift中使用。
□ 等于(a == b)。
□ 不等于(a != b)。
□ 大于(a > b)。
□ 小于(a < b)。
□ 大于等于(a >= b)。
□ 小于等于(a <= b)。
注意
在 Swift 語言中還支持恒等(3 個(gè)等號,===)和不恒等(一個(gè)感嘆號和兩個(gè)等號,!==)兩個(gè)比較操作符。這兩個(gè)操作符用來判斷兩個(gè)對象是否引用了同一個(gè)對象實(shí)例。更多關(guān)于這兩個(gè)操作符的細(xì)節(jié),將在后面介紹類和結(jié)構(gòu)體時(shí)詳細(xì)討論。
每一個(gè)比較操作符都返回一個(gè)Bool類型的值,所以,比較操作符會經(jīng)常用于if語句中,關(guān)于if語句的細(xì)節(jié)會在后面的章節(jié)中詳細(xì)討論。
下面是一些使用比較操作符的例子。
1 == 1 // true,因?yàn)?1 等于 1
2 != 1 // true,因?yàn)?2 不等于 1
2 > 1 // true, 因?yàn)?2大于 1
1 < 2 // true, 因?yàn)?1小于2
1 >= 1 // true,因?yàn)?1 大于等于 1
2 <= 1 // false,因?yàn)?2 并不小于等于 1
let name = "bill"
if name == "world" // 此處條件為false
{
println("yes")
}
else // 此處條件為true
{
println("no")
}
3.6 三元條件操作符
Swift中只有一個(gè)三元操作符。操作符的原型如下。
邏輯表達(dá)式?為true時(shí)的答案:為false時(shí)的答案
其實(shí)三元條件操作符和前面介紹的復(fù)合賦值操作符一樣,也是為了簡化表達(dá)式而存在的,所以并不是必須的,但使用該操作符卻能提升程序的開發(fā)效率,使程序看起來更美觀。
三元條件操作符實(shí)際上是簡化了下面的代碼。
if 邏輯表達(dá)式
{
為true時(shí)的答案
}
else
{
為false時(shí)的答案
}
下面是一個(gè)實(shí)際的例子,在該例子中分別演示了不使用三元邏輯操作符和使用三元邏輯操作符的情況。
var value:Int
var flag:Bool = true
// 不使用三元邏輯操作符的情況
if flag
{
value = 1
}
else
{
value = 2
}
// 使用三元邏輯操作符的情況
value = (flag ? 1 : 2)
3.7 區(qū)間操作符
區(qū)間操作符可以非常方便地確定一個(gè)區(qū)間,通常是一個(gè)數(shù)值的區(qū)間。并且可以枚舉這個(gè)區(qū)間中的每一個(gè)值。盡管區(qū)間操作符用起來很方便,但并不是所有的語言都支持區(qū)間操作符,對于靜態(tài)語言來說,Pascal 是支持區(qū)間操作符的。不過幸好 Swift 也支持區(qū)間操作符,這將會給我們編寫代碼帶來很多方便。
區(qū)間操作符分為閉區(qū)間操作符和半開半閉操作符。閉區(qū)間操作符使用3個(gè)點(diǎn)(...)表示,該操作符包含了區(qū)間兩端的值。而半開半閉操作符使用兩個(gè)點(diǎn)加一個(gè)小于號(..<)表示 ,該操作符左側(cè)端點(diǎn)的值會被包含,但不包含右側(cè)端點(diǎn)的值。
區(qū)間操作符在使用for-in循環(huán)枚舉數(shù)組或字典中元素時(shí)非常有用。
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
// i會從0循環(huán)到count – 1
for i in 0..<count
{
println("第 \(i + 1) 個(gè)人叫 \(names[i])")
}
執(zhí)行上面的代碼,會輸出如下的結(jié)果。
第 1 個(gè)人叫 Anna
第 2 個(gè)人叫 Alex
第 3 個(gè)人叫 Brian
第 4 個(gè)人叫 Jack
當(dāng)然,我們還可以使用閉區(qū)間對數(shù)值進(jìn)行循環(huán)。
for i in 1...5
{
print("index = \(i) ")
}
執(zhí)行上面的代碼,會輸出如下的內(nèi)容。
index = 1 index = 2 index = 3 index = 4 index = 5
注意
經(jīng)測試發(fā)現(xiàn),區(qū)間操作符是可以使用浮點(diǎn)數(shù)的,例如,1...1.2,不過使用浮點(diǎn)數(shù)會使Swift程序員不好處理。讀者自己測試下就知道了,如果使用 for-in語句,會無限循環(huán)下去,每次都會輸出很大的數(shù)。這可能是因?yàn)镾wift最開始確定的開發(fā)理念是盡可能滿足更多的表達(dá)方法,估計(jì)是能用浮點(diǎn)數(shù)的都可以使用浮點(diǎn)數(shù)了(如求余)。但可能還沒考慮全(編譯器未實(shí)現(xiàn)完整),所以在對區(qū)間操作符使用浮點(diǎn)數(shù)時(shí),就會出現(xiàn)無法預(yù)料的結(jié)果,大家還是別用浮點(diǎn)數(shù)了。如果要真用浮點(diǎn)數(shù),Swift最好用步長之類的東西。否則沒法循環(huán)了。
3.8 邏輯操作符
邏輯運(yùn)算的操作對象是邏輯布爾值。Swift支持基于C語言的3個(gè)標(biāo)準(zhǔn)邏輯運(yùn)算。
□ 邏輯非(!a)。
□ 邏輯與(a && b)。
□ 邏輯或(a || b)。
3.8.1 邏輯非
邏輯非運(yùn)算(!a)對一個(gè)布爾值取反,使得true變?yōu)閒alse,或使false變?yōu)閠rue。
邏輯非是一個(gè)前置操作符,需出現(xiàn)在操作數(shù)的前面,并且操作符和操作數(shù)之間不能加空格。讀作“非 a”或“對a取反”,現(xiàn)在來看下面的例子。
let allowed = false
if !allowed
{
println("allowed")
}
else
{
println("denied");
}
執(zhí)行這段代碼后,會輸出“allowed”。
3.8.2 邏輯與
邏輯與(a && b)表達(dá)了只有a和b的值都為true時(shí),整個(gè)表達(dá)式的值才會是true。只要任意一個(gè)值為false,整個(gè)表達(dá)式的值就為false。事實(shí)上,如果第一個(gè)值為false,那么是不去計(jì)算第二個(gè)值的,因?yàn)樗呀?jīng)不可能影響整個(gè)表達(dá)式的結(jié)果了。這被稱做“短路計(jì)算(short-circuit evaluation)”。
在下面的例子中,只有兩個(gè)Bool值都為true值的時(shí)候才會執(zhí)行if語句中的代碼,否則會執(zhí)行else中的代碼。
let entered = true
let passed = false
if entered && passed
{
println("Welcome!")
}
else
{
println("ACCESS DENIED")
}
在執(zhí)行上面的代碼后,會輸出“ACCESS DENIED”
3.8.3 邏輯或
邏輯或(a || b)是一個(gè)由兩個(gè)連續(xù)的“|”組成的中置運(yùn)算符。它表示了兩個(gè)邏輯表達(dá)式的其中一個(gè)為true,整個(gè)表達(dá)式就為true。
同邏輯與運(yùn)算類似,邏輯或也是“短路計(jì)算”的,當(dāng)左端的表達(dá)式為true時(shí),將不計(jì)算右邊的表達(dá)式了,因?yàn)樗豢赡芨淖冋麄€(gè)表達(dá)式的值了。
在下面的代碼中,第一個(gè)布爾值(hasKey)為 false,但第二個(gè)值(knowsPassword)為 true,所以整個(gè)表達(dá)是true,于是允許進(jìn)入:
let hasKey = false
let knowsPassword = true
if hasKey || knowsPassword
{
println("Welcome!")
}
else
{
println("ACCESS DENIED")
}
執(zhí)行這段代碼后,會輸出“Welcome!”。
3.8.4 組合邏輯
我們可以組合多個(gè)邏輯運(yùn)算來表達(dá)一個(gè)復(fù)合邏輯。
if entered && passed || hasKey || knowsPassword
{
println("Welcome!")
}
else
{
println("ACCESS DENIED")
}
執(zhí)行這段代碼后,會輸出“Welcome!”。
如果只是簡單地將邏輯操作符組合在一起,那么系統(tǒng)會從左到右依次計(jì)算,例如,對于這段代碼來說,會先計(jì)算“entered && passed”,然后用計(jì)算結(jié)果與hasKey進(jìn)行邏輯或,最后再用邏輯或的結(jié)果與knowsPassword進(jìn)行邏輯或。
3.8.5 使用圓括號指定優(yōu)先級
對于一個(gè)復(fù)雜的表達(dá)式,可能需要指定先運(yùn)算那一對操作數(shù),這就要使用圓括號來確定優(yōu)先級。例如,下面的表達(dá)式就會先將passed和hasKey進(jìn)行邏輯或,然后再與entered邏輯與,最后與knowsPassword邏輯或。
if entered&&(passed || hasKey) || knowsPassword
{
println("Welcome!")
}
else
{
println("ACCESS DENIED")
}
執(zhí)行這段代碼后,會輸出“Welcome!”。
如果邏輯表達(dá)式比較復(fù)雜,建議使用圓括號指定優(yōu)先級,這樣不僅不易出錯(cuò),而且也增加了程序的可讀性。
3.9 小結(jié)
盡管 Swift 語言支持的大多數(shù)操作符和其他語言類似,但對于剛?cè)腴T的程序員來說,最好仔細(xì)閱讀本章的內(nèi)容。因?yàn)?,如果對這些基本的操作符不了解或不能熟練使用的話,會在以后的學(xué)習(xí)和工作中遇到很大的困難。當(dāng)然,對于已有多年工作經(jīng)驗(yàn)的讀者來說,只需要看一下Swift特有的操作符(如區(qū)間操作符)即可,其他內(nèi)容可直接跳過。
- 掌握分布式跟蹤:微服務(wù)和復(fù)雜系統(tǒng)性能分析
- Docker源碼分析
- Android5.0新特性實(shí)戰(zhàn)
- 服務(wù)端開發(fā):技術(shù)、方法與實(shí)用解決方案
- 程序員度量:改善軟件團(tuán)隊(duì)的分析學(xué)
- 混沌工程:通過可控故障實(shí)驗(yàn)提升軟件系統(tǒng)可靠性
- Unity 2017經(jīng)典游戲開發(fā)教程:算法分析與實(shí)現(xiàn)
- 芯片改變世界
- React Cookbook中文版:87個(gè)案例帶你精通React框架
- AR與VR開發(fā)實(shí)戰(zhàn)
- 軟件工程:理論與實(shí)踐(第2版)
- DDD工程實(shí)戰(zhàn):從零構(gòu)建企業(yè)級DDD應(yīng)用
- R實(shí)戰(zhàn):系統(tǒng)發(fā)育樹的數(shù)據(jù)集成操作及可視化
- 軟件之美
- ChatGPT驅(qū)動軟件開發(fā):AI在軟件研發(fā)全流程中的革新與實(shí)踐