Swift:基础运算符

运算符是一种用来检查、改变或者合并值的特殊符号或组合符号。举例来说,加运算符( + )能够把两个数字相加(比如 let i = 1 + 2 )。更复杂的栗子包括逻辑与运算 && 比如 if enteredDoorCode && passedRetinaScan

Swift 在支持 C 中的大多数标准运算符的同时也增加了一些排除常见代码错误的能力。赋值符号( = )不会返回值,以防它被误用于等于符号( == )的意图上。算数符号( + , - , * , / , % 以及其他)可以检测并阻止值溢出,以避免你在操作比储存类型允许的范围更大或者更小的数字时得到各种奇奇怪怪的结果。你可以通过使用 Swift 的溢出操作符来选择进入值溢出行为模式。

Swift 提供了两种 C 中没有的区间运算符( a..<b 和 a...b ),来让你便捷表达某个范围的值。

这个章节叙述了 Swift 语言当中常见的运算符。高级运算符 则涵盖了 Swift 中的高级运算符,同时描述了如何定义你自己的运算符以及在你自己的类当中实现标准运算符。

专门用语

运算符包括一元、二元、三元:

  • 一元运算符对一个目标进行操作(比如-a)。一元前缀 运算符在目标之前直接添加(比如!b),同事一元后缀运算符直接在目标末尾添加(比如c!)。
  • 二元运算符对两个目标金鑫操作(比如2 + 3)同时因为他们出现在两个目标之间,所有是中缀。
  • 三元运算符操作三个目标。如同 CSwift语言也仅有一个三元运算符,三元条件运算符( a ? b : c )

受到运算符影响的值叫做操作数。在表达式 1 + 2 中, + 符号是一个二元运算符,其中的两个值 12 就是操作数

赋值运算符

赋值运算符( a = b )可以初始化或者更新 ab 的值:

1
2
3
let b = 10
var a = 4
a = b // a的值现在是10

如果赋值符号右侧是拥有多个值的元组,它的元素将会一次性地拆分成常量或者变量

1
2
let (x, y) = (1, 2)
// x 等于 1, 同时 y 等于 2

Objective-CC 不同,Swift 的赋值符号自身不会返回值。下面的语句是不合法的:

1
2
3
if x = y {
//这里不合法,因为x = y并不会返回任何值
}

这个特性避免了赋值符号 (=) 被意外地用于等于符号 (==) 的实际意图上。Swift 通过让 if x = y 非法来帮助你避免这类的错误在你的代码中出现。

算术运算符

Swift 对所有的数字类型支持四种标准算术运算符:
加 ( + )
减 ( - )
乘 ( * )
除 ( / )
CObjective-C 中的算术运算符不同,Swift 算术运算符默认不允许值溢出。你可以选择使用 Swift 的溢出操作符(比如 a &+ b)来行使溢出行为。
加法运算符同时也支持 String 的拼接:“hello” + "world"

余数运算符

余数运算符( a % b )可以求出多少个 b 的倍数能够刚好放进 a 中并且返回剩下的值(就是我们所谓的余数)。
b为负数时它的正负号被忽略掉了。这意味着 a % ba % -b 能够获得相同的答案。

1
2
3
4
9 % 4 // equals -1
-9 % 4 // equals -1
//9 % -4 和 9 % 4 相等

一元减号运算符

数字值的正负号可以用前缀 来切换,我们称之为 一元减号运算符:

1
2
3
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"

一元加号运算符

一元加号运算符 ( + )直接返回它操作的值,不会对其进行任何的修改:
尽管一元加号运算符实际上什么也不做,你还是可以对正数使用它来让你的代码对一元减号运算符来说显得更加对称。感觉没什么用!!

1
2
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6

组合赋值符号

如同 CSwift 提供了由赋值符号( = )和其他符号组成的 组合赋值符号 。一个加赋值符号的栗子 ( += )

1
2
var c = 1
c += 2 // c is now equal to 3

比较运算符

Swift 支持所有 C 的标准比较运算符:

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

Swift 同时也提供两个等价运算符(=== 和 !== ),你可以使用它们来判断两个对象的引用是否相同。

比较运算符通常被用在条件语句当中,比如说 if 语句:

1
2
3
4
5
6
let name = "world"
if name == "world" {
print("Hello, world")
} else {
print("I`m sorry \(name), but I don`t recongnize you")
}

你同样可以比较拥有同样数量值元组,只要元组中的每个值都是可比较的。比如说, IntString 都可以用来比较大小,也就是说 (Int,String) 类型的元组就可以比较。一般来说, Bool 不能比较,这意味着包含布尔值的元组不能用来比较大小。

元组以从左到右的顺序比较大小,一次一个值,直到找到两个不相等的值为止。如果所有的值都是相等的,那么就认为元组本身是相等的。比如说:

1
2
3
(1, "zebra") < (2, "apple") // true because 1 is less than 2
(3, "apple") < (3, "bird") // true because 3 is equal to 3, and "apple" is less than "bird"
(4, "dog") == (4, "dog") // true because 4 is equal to 4, and "dog" is equal to "dog"

注意:
Swift 标准库包含的元组比较运算符仅支持小于七个元素的元组。要比较拥有七个或者更多元素的元组,你必须自己实现比较运算符。

三元条件运算符

三元条件运算符是一种有三部分的特殊运算,它看起来是这样的: question ? answer1 : answer2。这是一种基于 question 是真还是假来选择两个表达式之一的便捷写法。如果 question 是真,则会判断为 answer1 并且返回它的值;否则,它判断为 answer2 并且返回它的值。
举个简单例子:

1
2
3
4
5
if question {
answer1
} else {
answer2
}

合并空值运算符

合并空值运算符 ( a ?? b)如果可选项 a 有值则展开,如果没有值,是 nil ,则返回默认值 b。表达式 a 必须是一个可选类型。表达式 b 必须与 a 的储存类型相同。

合并空值运算符是下边代码的缩写:a != nil ? a! : b

上边的代码中,三元条件运算符强制展开( a! )储存在 a 中的值,如果 a 不是 nil 的话,否则就返回b 的值。合并空值运算符提供了更加优雅的方式来封装这个条件选择和展开操作,让它更加简洁易读。

区间运算符

Swift 包含了两个 区间运算符 ,他们是表示一个范围的值的便捷方式。

闭区间运算符

闭区间运算符( a...b )定义了从 ab 的一组范围,并且包含 aba 的值不能大于 b

遍历你需要用到的所有数字时,使用闭区间运算符是个不错的选择,比如说在 for-in 循环当中:

1
2
3
4
5
6
7
8
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

半开区间运算符

半开区间运算符( a..<b )定义了从 ab 但不包括 b 的区间,即 半开 ,因为它只包含起始值但并不包含结束值。(注:其实就是左闭右开区间。)如同闭区间运算符, a 的值也不能大于 b ,如果ab 的值相等,那返回的区间将会是空的。

半开区间在遍历基于零开始序列比如说数组的时候非常有用,它从零开始遍历到数组长度(但是不包含):

1
2
3
4
5
6
7
8
9
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

单侧区间

闭区间有另外一种形式来让区间朝一个方向尽可能的远——比如说,一个包含数组所有元素的区间,从索引 2 到数组的结束。在这种情况下,你可以省略区间运算符一侧的值。因为运算符只有一侧有值,所以这种区间叫做单侧区间。比如说:

1
2
3
4
5
6
7
8
9
10
for name in names[2...] {
print(name)
//Brian
//Jack
}
for name in names[1...2] {
print(name)
//Alex
//Brian
}

半开区间运算符同样可以有单侧形式,只需要写它最终的值。和你两侧都包含值一样,最终的值不是区间的一部分。举例来说:

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

单侧区间也可以 在其他上下文中使用 ,不仅仅是下标。你不能遍历省略了第一个值的单侧区间,因为遍历根本不知道该从哪里开始。你可以遍历省略了最终值的单侧区间;总之,由于区间无限连续,你要确保给循环添加一个显式的条件。你同样可以检测单侧区间是否包含特定的值,就如下面的代码所述。

1
2
3
4
let range = ...5
range.contains(9) //false
range.contains(4) //true
range.contains(-1)//true

逻辑运算符

逻辑运算符可以修改或者合并布尔逻辑值 truefalseSwift 支持三种其他基于 C 的语言也包含的标准逻辑运算符

  • 逻辑 非(!a)
  • 逻辑 与(a && b)
  • 逻辑 或(a || b)

逻辑非运算符

逻辑非运算符( !a )会转换布尔值,把 true 变成 false , 把 false 变成 true

逻辑与运算符

逻辑与运算符( a && b )需要逻辑表达式的两个值都为 true ,整个表达式的值才为 true

如果任意一个值是 false ,那么整个表达式的结果会是 false 。事实上,如果第一个值是 false ,那么第二个值就会被忽略掉了,因为它已经无法让整个表达式再成为 true 。这就是所谓的 短路计算 。

逻辑或运算符

逻辑或运算符( a || b )是一个中缀运算符,它由两个相邻的管道字符组成。你可以使用它来创建两个值之间只要有一个为 true 那么整个表达式就是 true 的逻辑表达式。

如同上文中的逻辑与运算符,逻辑或运算符也使用短路计算来判断表达式。如果逻辑或运算符左侧的表达式为 true那么右侧则不予考虑了,因为它不会影响到整个逻辑表达式的结果。
你可以组合多个逻辑运算符来创建一个更长的组合表达式:

混合逻辑运算

你可以组合多个逻辑运算符来创建一个更长的组合表达式:

1
2
3
4
5
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}

这个栗子使用了多个 && 和 || 运算符来创建组合表达式。不过, && 和 || 仍旧只能够操作两个值,它实际上是三个更小的表达式链接而成。这个栗子可以读作:

如果我们输入了正确的密码并通过了视网膜扫描,或者如果我们有合法的钥匙或者我们知道紧急超驰密码,就允许进入。

注意:
Swift 语言中逻辑运算符 &&||左相关的,这意味着多个逻辑运算符组合的表达式会首先计算最左边的子表达式

显式括号

很多时候虽然不被要求,但使用括号还是很有用的,这能让复杂的表达式更容易阅读。在上文当中的门禁栗子里,把前边部分的表达式用圆括号括起来就会让整个组合表达式的意图更加明显:

1
2
3
4
5
6
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// prints "Welcome!"

圆括号把前边的两个值单独作为一部分来考虑,这样使整个表达式的意图清晰明显。组合表达式的输出并没有改变,但是整个意图变得清晰易读。 可读性永远是第一位的 ;当需要的时候,使用圆括号让你的意图更加明确

摘自:swift 官网
所有代码在Xcode9 Swift4 环境编译没问题,代码戳这里 https://github.com/keshiim/LearnSwift4

坚持原创技术分享,您的支持将鼓励我继续创作!