基本运算符
Swift 中的运算符区分了基本运算符和高级运算符。 本章节我们主要学习基本运算符,对高级运算符进行一定的了解。
根据操作数的不同,Swift中的基本运算符包括一元运算符、二元运算符、三元运算符:
- 一元运算符:对一个目标进行操作(比如 -a )。一元前缀运算符在目标之前直接添加(比如 !b ),一元后缀运算符直接在目标末尾添加(比如 c! )。
- 二元运算符:对两个目标进行操作(比如 2 + 3 ),因为它们出现在两个目标之间,所以是中缀。
- 三元运算符:操作三个目标。如同 C,Swift语言也仅有一个三元运算符,三元条件运算符( a ? b : c )。
受到运算符影响的值叫做操作数。在表达式 1 + 2 中, + 符号是一个二元运算符,其中的两个值 1 和 2 就是操作数。
赋值运算符
let b = 10
var a = 5
a = b
// a 的值现在是 10
let (x, y) = (1, 2)
// x 等于 1, 同时 y 等于 2
//Swift 的赋值符号自身不会返回值。下面的语句是不合法的:
if x = y {
// 这是不合法的, 因为 x = y 并不会返回任何值。
}
算术运算符
Swift 对所有的数字类型支持四种标准算术运算符:
/*
加 ( + )
减 ( - )
乘 ( * )
除 ( / )
*/
1 + 2 // equals 3
5 - 3 // equals 2
2 * 3 // equals 6
10.0 / 2.5 // equals 4.0
// 加法运算符同时也支持 String 的拼接:
"hello, " + "world"
// equals "hello, world"
余数运算符
余数运算符( a % b )可以求出多少个 b 的倍数能够刚好放进 a 中并且返回剩下的值(就是我们所谓的余数)。
余数运算符( % )同样会在别的语言中称作 取模运算符 。总之,严格来讲的话这个行为对应着 Swift 中对负数的操作,所以余数要比模取更合适。
//如图:
//你可以给 9 当中放进两个 4 去,这样就得到了 1 这个余数 (橘黄色的部分)。
9 % 4 // equals 1
// 即
9 = 4*2 + 1
余数运算符对负数同样适用:
-9 % 4 // equals -1
// 即
-9 = (4 * -2) + -1
// a % b 与 a % -b 能够获得相同的答案。
一元减号运算符
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元减号运算符( - )直接在要进行操作的值前边放置,不加任何空格。
一元加号运算符
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
一元加号运算符( + )直接返回它操作的值,不会对其进行任何的修改。
组合赋值符号
由赋值符号( = )和其他符号组成的 组合赋值符号 。如 (+= , -=)
var a = 1
a += 2
// 即 a = a + 2
var b = 1
b -= 1
// 即 b = b - 1
print("a=\(a),b=\(b)")
// 输出:a=3,b=0
==组合运算符不会返回任何值。例如: let b = a += 2 是错误的。==
比较运算符
Swift 支持以下的比较运算符:
// 等于 a == b
// 不等于 a != b
// 大于 a > b
// 小于 a < b
// 大于等于 a >= b
// 小于等于 a <= b
Swift 也提供恒等(===)和不恒等(!==)这两个比较符来判断两个对象是否引用同一个对象实例。
每个比较运算都返回了一个标识表达式是否成立的布尔值
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”
如果两个元组的元素相同,且长度相同的话,元组就可以被比较。
比较元组大小会按照从左到右、逐值比较的方式,直到发现有两个值不等时停止。如果所有的值都相等,那么这一对元组我们就称它们是相等的。例如:
(1, "zebra") < (2, "apple") // true,因为 1 小于 2
(3, "apple") < (3, "bird") // true,因为 3 等于 3,但是 apple 小于 bird
(4, "dog") == (4, "dog") // true,因为 4 等于 4,dog 等于 dog
Swift 标准库只能比较七个以内元素的元组比较函数。
三元运算符
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight 现在是 90
空合运算符(Nil Coalescing Operator)
空合运算符(a ?? b)将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回一个默认值 b。
表达式 a 必须是 Optional 类型。
let defaultColor = "red"
var color: String? //默认值为 nil
var nowColor = color ?? defaultColor
print(nowColor)
color 定义为一个可选类型Optional,默认值为nil,我们可以使用空合运算符去判断其值,并指定默认值
区间运算符
//闭区间运算符: a...b 包含两端
for index in 1...5 {
print("\(index) * 5 = \(index * 5)")
}
// 1 * 5 = 5
// 2 * 5 = 10
// 3 * 5 = 15
// 4 * 5 = 20
// 5 * 5 = 25
//半开区间运算符: a..<b, 包含a,但是不包含b
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("第 \(i + 1) 个人叫 \(names[i])")
}
// 第 1 个人叫 Anna
// 第 2 个人叫 Alex
// 第 3 个人叫 Brian
// 第 4 个人叫 Jack
//单侧区间: 可以往一侧无限延伸的区间
//例如,一个包含了数组从索引 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
逻辑运算符
逻辑运算符的操作对象是逻辑布尔值。
-
逻辑非(!a): 操作数前没有空格,对一个布尔值取反
-
逻辑与(a && b): 真真为真,否则为假,存在短路计算
-
逻辑或(a || b): 有一个为真即为真,存在短路计算
我们也可以组合多个逻辑运算符来表达一个复合逻辑:
// 优先计算最左边的子表达式
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// 输出“Welcome!”
// 也可以使用 括号 明确优先级, 更加易读
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// 输出“Welcome!”
高级运算符
高级运算符的详细介绍请参考:https://www.cnswift.org/advanced-operators
高级运算符主要包含:位运算符和移位运算符。
按位取反运算符
按位取反运算符(** ~ **)对一个数值的全部比特位进行取反:
// 操作数前不能有空格
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // 等于 0b11110000
按位与运算符
按位与运算符(** & **) 对两个数的比特位进行合并。只有当两个数的对应位都为 1 的时候,新数的对应位才为 1:
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
按位或运算符
按位或运算符(** | **)可以对两个数的比特位进行比较。它返回一个新的数,只要两个数的对应位中有任意一个为 1 时,新数的对应位就为 1
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // 等于 11111110
按位异或运算符
按位异或运算符,或称“排外的或运算符”(^),可以对两个数的比特位进行比较。当两个数的对应位不相同时,新数的对应位就为 1,并且对应位相同时则为 0:
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // 等于 00010001
按位左移、右移运算符
按位左移运算符(** << *)和 按位右移运算符( >> **)*可以对一个数的所有位进行指定位数的左移和右移。
对一个数进行按位左移或按位右移,相当于对这个数进行乘以 2 或除以 2 的运算。
将一个整数左移一位,等价于将这个数乘以 2,同样地,将一个整数右移一位,等价于将这个数除以 2。
对无符号整数进行移位的规则如下:
- 已存在的位按指定的位数进行左移和右移。
- 任何因移动而超出整型存储范围的位都会被丢弃。
- 用 0 来填充移位后产生的空白位。
溢出运算符
当向一个整数类型的常量或者变量赋予超过它容量的值时,Swift 默认会报错,而不是允许生成一个无效的数。这个行为为我们在运算过大或者过小的数时提供了额外的安全性。
Swift 提供的三个溢出运算符来让系统支持整数溢出运算。这些运算符都是以 &开头的:
- 溢出加法 &+
- 溢出减法 &-
- 溢出乘法 &*
运算符函数
类和结构体可以为现有的运算符提供自定义的实现,被称为运算符重载。
下面的例子展示了如何让自定义的结构体支持加法运算符(+)。算术加法运算符是一个二元运算符,因为它是对两个值进行运算,同时它还可以称为中缀运算符,因为它出现在两个值中间。
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
// 输出: Vector2D(x: 5.0, y: 5.0)
print(combinedVector)
除了可以扩展支持二元运算符,也可以扩展支持一元运算符。
一元运算符只运算一个值。当运算符出现在值之前时,它就是前缀的(例如 -a),而当它出现在值之后时,它就是后缀的(例如 b!)。
要重载一元运算符,需要在声明运算符函数的时候在 func 关键字之前指定 prefix 或者 postfix 修饰符:
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
// 输出: Vector2D(x: -3.0, y: -4.0)
print(negative)
同样,也可以对复合赋值运算符(+=)进行重载,但是:赋值运算符(=),三元条件运算符 (a ? b : c)无法进行重载。
自定义运算符
除了实现标准运算符,在 Swift 中还可以声明和实现自定义运算符。
可以使用 operator 关键字在全局作用域内进行定义,同时还要指定 prefix、infix 或者 postfix 修饰符:
//定义了一个新的名为 +++ 的前缀运算符
prefix operator +++
虽然自定义了运算符,但是对于这个运算符,在 Swift 中并没有已知的意义,因此还需要进行重载实现其意义:
prefix operator +++
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func += (left: inout Vector2D, right: Vector2D) {
left = left + right
}
//inout关键字: 通过一个函数改变函数外面变量的值(将一个值类型参数以引用方式传递)
static prefix func +++ (vector: inout Vector2D) -> Vector2D {
//+= 同样是重载过的
vector += vector
return vector
}
}
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// toBeDoubled 和 afterDoubling 输出:Vector2D(x: 2.0, y: 8.0)
print(toBeDoubled)
print(afterDoubling)