天天看點

Swift程式設計三(基本運算符)基本運算符

案例代碼下載下傳

基本運算符

一個運算符是一個特殊的符号,或者你使用來檢查,更改或合并值的短語。例如,加法運算符(+)對兩個數字相加,如:let i = 1 + 2,和AND邏輯運算符(&&)組合兩個布爾值,如:&if enteredDoorCode && passedRetinaScan

Swift支援大多數标準C運算符,并改進了幾種消除常見編碼錯誤的功能。指派運算符(=)不傳回值,以防止在相等運算(==)意圖時錯誤地使用它。算術運算符(+,-,*,/,%等等)檢測和禁止值溢出,來避當工作時資料比存儲它們的類型所允許範圍更大或更小而發生免意外的結果。在面對數值溢出行為可以選擇使用溢出運算符,在溢出運算符中描述。

Swift還提供了在C中不存在的區間運算符,例如a…<b和a…b表示一系列值範圍的快捷方式。

本章介紹Swift中的常用運算符。進階運算符涵蓋了Swift的進階運算符,并描述了如何定義自定義運算符并為自定義類型實作标準運算符。

術語

運算符是一進制的,二進制的或三元的:

  • 一進制運算符作用于單個目标上(例如-a)。一進制字首運算符出現在它們的目标之前(例如!b),而一進制字尾運算符緊跟在它們的目标之後(例如c!)。
  • 二進制運算符作用于兩個目标(例如2 + 3),并且是中綴,因為它們出現在兩個目标之間。
  • 三元運算符在三個目标上操作。與C一樣,Swift隻有一個三元運算符,即三元條件運算符(a ? b : c)。

運算符影響的值是操作數。在表達式1 + 2中,符号+是二進制運算符,它的兩個操作數是值1和2。

指派運算符

該指派運算符(a = b)用b的值初始化或更新a的值

let b = 10
var a = 5
a = b//a的值為10
           

如果指派的右側是具有多個值的元組,則其元素可以一次分解為多個常量或變量:

let (x, y) = (1, 2)
           

與C和Objective-C中的指派運算符不同,Swift中的指派運算符本身不傳回值。以下聲明無效:

if let x = y {
    //這是無效的,因為x = y不傳回值
}
           

此功能可防止在實際使用等于運算符(==)時意外使用指派運算符(=)。通過使if x = y無效,Swift可以幫助您避免代碼中的這類錯誤。

算術運算符

Swift支援所有數字類型的四個标準算術運算符:

  • 加法(+)
  • 減法(-)
  • 乘法(*)
  • 除法(/)
1 + 2
5 - 3
2*3
10.0/2.5
           

與C和Objective-C中的算術運算符不同,Swift算術運算符預設情況下不允許值溢出。您可以通過使用Swift的溢出運算符來選擇值溢出行為(例如 a &+ b)。請參閱溢出運算符。

加法運算符也支援String連接配接:

"hello, " + "world"//等于"hello, world"
           

取餘運算符

取餘運算符(a % b)a的多少倍适合b,并傳回剩下值(被稱為剩餘部分)。

注意:取餘運算符(%)在其他語言也稱為模運算符。然而,它在Swift中對負數的行為意味着,嚴格來說,它是一個餘數而不是模運算。

以下是取餘運算符的工作原理。要計算9 % 4,你首先計算出4的多少倍适合9:

Swift程式設計三(基本運算符)基本運算符

你可以在9裡面放兩個4,其餘的是1(用橙色表示)。

在Swift中,這将寫成:

9%4//等于1
           

為确定a % b的答案,%運算符計算以下等式并将remainder作為其輸出傳回

a = (b x some multiplier) + remainder

some multiplierba是最适合的内部倍數。

插入9和4輸入此等式可得出:

9=(4x 2)+1

在計算負值a的餘數時應用相同的方法:

-9%4//等于-1
           

插入-9和4輸入等式産生:

-9=(4x -2)±1

給出餘數值-1。

對于負值b,忽略符号b。這意味着a % b和a % -b的結果相同。

一進制減運算符

可以使用字首-(稱為一進制減運算符)來切換數值的符号:

let three = 3
let minusThree = -three//-3
let plusThree = -minusThree//3
           

一進制減運算符(-)直接位于它作用的值之前,沒有任何空格。

一進制加運算符

一進制加運算符(+)隻傳回其所作用的值,沒有任何變化:

let minusSix = -6
let alsoMinusSix = +minusSix//6
           

雖然一進制加運算符實際上沒有做任何事情,但是當使用一進制減運算符作為負數時,您可以使用它來為代碼提供正數的對稱性。

複合指派運算符

與C一樣,Swift提供了将指派運算符(=)與另一個操作相結合的複合指派運算符。一個例子是加法指派運算符(+=):

var a = 1
a += 2//3
           

表達式a += 2是a = a + 2的簡寫。實際上,相加和指派組合成一個同時執行兩個任務的運算符。

注意: 複合指派運算符不傳回值。例如,你不能寫let b = a += 2。

有關Swift标準庫提供的運算符的資訊,請參閱運算符聲明。

比較運算符

Swift支援所有标準C 比較運算符:

  • 等于(a == b)
  • 不等于(a != b)
  • 大于(a > b)
  • 小于(a < b)
  • 大于或等于(a >= b)
  • 小于或等于(a <= b)

    注意: Swift還提供了兩個恒等運算符( === 和 !== ),用于測試兩個對象引用是否都引用同一個對象執行個體。有關更多資訊,請參閱Identity Operators。

每個比較運算符都傳回一個Bool值,以該語句是否為true:

1 == 1//true
2 != 1//true
2 > 1//true
1 < 2//true
1 >= 1//true
2 <= 1//false
           

比較運算符通常用于條件語句,例如if語句:

let name = "world"
if name == "world" {
    print("hello, world")
} else {
    print("I'm sorry \(name), but I don't recognize you")
}
//列印 "hello, world", 因為name等于"world".
           

有關該if語句的更多資訊,請參閱控制流。

如果它們具有相同的類型和相同的值,則可以比較兩個元組。元組從左到右進行比較,一次一個值,直到比較找到兩個不相等的值。比較這兩個值,并且該比較的結果确定元組比較的總體結果。如果所有元素都相等,則元組本身是相等的。例如:

(1, "zebra") < (2, "apple")   // true 因為 1 is 小于 2; "zebra" and "apple" 不會被比較
(3, "apple") < (3, "bird")    // true 因為 3 is 等于 3, and "apple" 小于 "bird"
(4, "dog") == (4, "dog")      // true 因為 4 is 等于 4, and "dog" 等于 "dog"
           

在上面的示例中,您可以在第一行看到從左到右的比較行為。因為1小于2,(1, “zebra”)被認為小于(2, “apple”),不管元組中的任何其他值。"zebra"不小于"apple"這不要緊,,因為比較已經由元組的第一個元素決定。但是,當元組的第一個元素相同時,它們的第二個元素會被比較 - 這就是第二行和第三行發生的情況。

僅當運算符可以應用于相應元組中的每個值時,才能将元組與給定運算符進行比較。例如,下面的代碼所示,您可以比較(String, Int)兩個類型的元組,因為可以使用<運算符比較String和Int兩者的值。相反,兩個(String, Bool)類型的元組無法與<運算符進行比較,因為<運算符不能應用于Bool值。

("blue", -1) < ("purple", 1)        // 正确, 結果:true
("blue", false) < ("purple", true)  // 錯誤 因為 < 不能比較 Boolean 值
           

注意: Swift标準庫包含的元組比較運算符,元組必須少于7個元素。要将七個或更多元素的元組進行比較,您必須自己實作比較運算符。

三元條件運算符

所述三元條件運算符是由question ? answer1 : answer2形式的三個部分組成的特殊操作。它是根據question是真還是假來評估兩個表達式之一的快捷方式。如果question為true,則計算并傳回answer1的值; 否則,它會評估并傳回answer2的值。

三元條件運算符是以下代碼的簡寫:

if question {
    answer1
} else {
    answer2
}
           

這是一個例子,它計算表格行的高度。如果行有标題,行高應該比内容高度高50個點,如果行沒有标題,則行高應該高20個點:

let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight 等于 90
           

上面的示例是以下代碼的簡寫:

let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
    rowHeight = contentHeight + 50
} else {
    rowHeight = contentHeight + 20
}
// rowHeight 等于 90
           

第一個示例使用三元條件運算符意味着rowHeight可以在單行代碼上設定正确的值,這比第二個示例中使用的代碼更簡潔。

三元條件運算符提供了一種有效的簡寫,用于決定要考慮兩個表達式中的哪一個。但是,請謹慎使用三元條件運算符。如果過度使用,它的簡潔性會導緻難以閱讀的代碼。避免将三元條件運算符的多個執行個體組合到一個複合語句中。

Nil-Coalescing運算符

Nil-Coalescing運算符(a ?? b)如果可選值a包含一個值則進行解包,如果是nil傳回一個預設b值。表達式a始終是可選類型。表達式b必須與存儲在a中的類型比對。

nil-coalescing運算符是下面代碼的簡寫:

a != nil ? a! : b
           

上面的代碼使用三元條件運算符和強制解包(a!)當a不是nil時來通路内部包裹的a值,否則傳回b。nil-coalescing運算符提供了一種更簡潔的方式來以簡潔易讀的形式封裝此條件檢查和展開。

注意: 如果值為a不是nil,則不評估b的值。這被稱為短路評估。

下面的示例使用nil-coalescing運算符在預設顔色名稱和可選的使用者定義顔色名稱之間進行選擇:

let defaultColorName = "red"
var userDefinedColorName: String?   // 預設是 nil

var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 是 nil, 是以 colorNameToUse 被設定為預設的 "red"
           

該userDefinedColorName變量被定義為可選的String,具有預設值nil。因為userDefinedColorName是可選類型,您可以使用nil-coalescing運算符來考慮其值。在上面的示例中,運算符用于确定叫做colorNameToUse的String變量的初始值。因為userDefinedColorName是nil,userDefinedColorName ?? defaultColorName表達式傳回defaultColorName的值,否則為"red"。

如果為非nil值指派userDefinedColorName并再次執行nil-coalescing運算符檢查,userDefinedColorName則使用包含在内的值而不是預設值:

userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 不是 nil, 是以 colorNameToUse 被設定為 "green"
           

區間運算符

Swift包含多個區間運算符,它們是表示一系列值的快捷方式。

閉區間運算符

閉區間運算符(a…b)限定了從運作範圍a到b,并且包括這些值a和b。值a不得大于b。

當在您希望使用所有值的範圍内進行疊代時,閉區間運算符非常有用,例如使用for- in循環:

for index in 1...5 {
    print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
           

有關for- in循環的更多資訊,請參閱控制流。

半開區間運算符

所述半開區間運算符(a…<b)限定了從運作範圍a到b,但不包括b。它被認為是半開放的,因為它包含它的第一個值,但不包含它的最終值。與閉區域運算符一樣,值a不得大于b。如果值a等于b,則結果範圍将為空。

當您使用基于零的清單(如數組)時,半開範圍特别有用,其中計算清單的長度(但不包括)非常有用:

let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
    print("Person \(i + 1) is called \(names[i])")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
           

請注意,該數組包含四個項目,但0…<count隻計算3(數組中最後一項的索引),因為它是半開放範圍。有關數組的更多資訊,請參閱數組。

單向區間

閉區域運算符有一個替代形式,用于在一個方向上盡可能繼續的範圍 - 例如,包括從索引2到數組末尾的數組的所有元素的範圍。在這些情況下,您可以省略範圍運算符一側的值。這種範圍稱為單側範圍,因為運算符僅在一側具有值。例如:

for name in names[2...] {
    print(name)
}
// Brian
// Jack

for name in names[...2] {
    print(name)
}
// Anna
// Alex
// Brian
           

半開區間運算符也具有單側形式,僅使用其最終值編寫。就像在兩側都包含值一樣,最終值不是範圍的一部分。例如:

for name in names[..<2] {
    print(name)
}
// Anna
// Alex
           

單向區間可以在其他上下文中使用,而不僅僅在下标中使用。您不能疊代忽略第一個值的單側範圍,因為不清楚疊代應該從何處開始。您可以疊代忽略其最終值的單向區間; 但是,因為範圍無限期地繼續,請確定為循環添加顯式結束條件。您還可以檢查單向區間是否包含特定值,如下面的代碼所示。

let range = ...5
range.contains(7)   // false
range.contains(4)   // true
range.contains(-1)  // true
           

邏輯運算符

邏輯運算符修改或組合布爾邏輯值true和false。Swift支援基于C語言的三個标準邏輯運算符:

  • 邏輯NOT(!a)
  • 邏輯AND()a && b
  • 邏輯OR()a || b

邏輯非運算符

的邏輯非運算符(!a)反轉一個布爾值,使得true成為false,或者false變true。

邏輯非運算符是字首運算符,并且在它運作的值之前立即出現,沒有任何空格。它可以讀作“not a”,如下例所示:

let allowedEntry = false
if !allowedEntry {
    print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
           

!allowedEntry短語可以讀作“如果非allowedEntry。”後續行僅在“非allowedEntry”為真時執行; 也就是說allowedEntry為false

在這個例子中,仔細選擇布爾常量和變量名稱有助于保持代碼的可讀性和簡潔性,同時避免雙重否定或混淆邏輯語句。

邏輯AND運算符

邏輯AND運算符(a && b)建立邏輯表達式,其中這兩個值必須為true整體表達式才為true。如果任一值false,則整體表達式将是false。實際上,如果第一個值是false,則第二個值不會被計算,因為它不可能使整個表達式等于true。這被稱為短路評估。

此示例考慮兩個Bool值,并且隻有兩個值都為true時允許執行:

let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
           

邏輯OR運算符

邏輯OR運算符(a || b)是來自兩個相鄰|字元制成中綴運算符。您可以使用它來建立邏輯表達式,其中有一個或兩個值為true則整個表達式是true。

與上面的邏輯AND運算符一樣,邏輯OR運算符使用短路評估來考慮其表達式。如果邏輯OR表達式的左側是true,則不評估右側,因為它不能更改整個表達式的結果。

在下面的示例中,第一個Bool值(hasDoorKey)是false,但第二個值(knowsOverridePassword)是true。因為有一個值是true,整個表達式也會計算為true,并允許通路:

let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "Welcome!"
           

結合邏輯運算符

您可以組合多個邏輯運算符來建立更長的複合表達式:

if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "Welcome!"
           

此示例使用多個 &&和||運算符建立更長的複合表達式。然而&&和||運算符仍然隻運作兩個值,是以這實際上是三個較小的表達式連結在一起。該示例可以了解為:

如果我們輸入了正确的門禁密碼并通過了視網膜掃描,或者我們有一個有效的門鑰匙,或者我們知道緊急覆寫密碼,那麼允許通路。

基于enteredDoorCode、passedRetinaScan和hasDoorKey的值,前兩個子表達式是false。但是,緊急覆寫密碼是true,是以整個複合表達式仍然評估為true。

注意: Swift邏輯運算符&&和||是左結合,這意味着與多個邏輯運算符複合表達式首先評估最左邊的子表達式。

明确的括号

當它們不是嚴格需要有時包含括括号是有用的,以使複雜表達的意圖更容易閱讀。在上面的進門的示例中,在複合表達式的第一部分周圍添加括号以使其意圖明顯是有用的:

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "Welcome!"
           

括号清楚地表明前兩個值被視為整體邏輯中單獨可能狀态的一部分。複合表達式的輸出不會改變,但讀者的整體意圖更清晰。可讀性始終優于簡潔; 使用括号,幫助他們明确你的意圖。