The Swift Programming Language-官方教程精译Swift(3)基本运算符

运算符是检查, 改变, 合并值的特殊符号或短语. 例如, 加号 + 把计算两个数的和(如 let i = 1 + 2). 复杂些的运行算包括逻辑与&&(如 if enteredDoorCode && passedRetinaScan), 还有自增运算符 ++i 这样让自身加一的便捷运算.

Swift支持大部分标准C语言的运算符, 且改进许多特性来减少常规编码错误. 如, 赋值符 = 不返回值, 以防止错把等号 == 写成赋值号 = 而导致Bug. 数值运算符( + , -, *, /, %等)会检测并不允许值溢出, 以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果. 当然允许你选择使用Swift的溢出运算符来玩溢出. 具体使用请移步溢出运算符.

区别于C语言, 在Swift中你可以对浮点数进行取余运算( % ), 还提供了C语言没有的表达两数之间的值的区间运算符, ( a..b 和 a...b ), 这方便我们表达一个区间内的数值.

本章节只描述了Swift中的基本运算符, 高级运算符包含了高级运算符,及如何自定义运算符, 及如何进行自定义类型的运算符重载.

术语

运算符有一目, 双目和三目运算符.

一目运算符对单一操作对象操作, 如 -a.

一目运算符分前置符和后置运算符, 前置运算符需紧排操作对象之前, 如 !b, 后置运算符需紧跟操作对象之后,如 i++,

双目运算符操作两个操作对象, 如 2 + 3. 是中置的, 因为它们出现在两个操作对象之间.

三目运算符操作三个操作对象, 和C语言一样, Swift只有一个三目运算符, 就是三目条件运算符 a ? b : c.

受运算符影响的值叫操作数, 在表达式 1 + 2 中, 加号 + 是双目运算符, 它的两个操作数是值 1 和 2.

赋值运算符

赋值运算 a = b, 表示用 b 的值来初始化或更新 a 的值.

1 let b = 10
2 var a = 5
3 a = b
4 // a 现在等于 10 

如果赋值的右边是一个多元组, 它的元素可以马上被分解多个变量或变量

1 let (x, y) = (1, 2)
2 // 现在 x 等于 1, y 等于 2 

与C语言和Objective-C不同, Swift的赋值操作并不返回任何值. 所以以下代码是错误的:

1 if x = y {
2     // 此句错误, 因为 x = y 并不返回任何值
3 } 

这个特性使得你无法把==错写成=了, 由于if x = y是错误代码, Swift从底层帮你避免了这些代码错误.

数值运算

Swift让所有数值类型都支持了基本的四则运算:

加法 +

减法 -

乘法 *

除法 /

1 1 + 2       // 等于 3
2 5 - 3       // 等于 2
3 2 * 3       // 等于 6
4 10.0 / 2.5  // 等于 4.0 

与C语言和Objective-C不同的是, Swift默认不允许在数值运算中出现溢出情况. 但你可以使用Swift的溢出运算符来达到你有目的的溢出, (如 a &+ b ). 详情请移步: 溢出运算符.

加法操作 + 也用于字符串的拼接:

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

两个字符类型或一个字符类型和一个字符串类型, 相加会生成一个新的字符串类型:

1 let dog: Character = "??"
2 let cow: Character = "??"
3 let dogCow = dog + cow
4 // dogCow 现在是 "????" 

详细请点击 字符,字符串的拼接.

求余运算

求余运算 a % b 是计算 b 的多少倍刚刚好可以容入 a , 多出来的那部分叫余数.

注意:求余运算(%)在其他语言也叫取模运算. 然而严格说来, 我们看该运算符对负数的操作结果, 求余 比 取模 更合适些.

我们来谈谈取余是怎么回事, 计算 9 % 4, 你先计算出4的多少倍会刚好可以容入 9 中.

2倍, 非常好, 那余数是1 (用‘*‘标出)

在Swift中这么来表达

1  9 % 4    // 等于 1 

为了得到 a % b 的结果, %计算了以下等式, 并输出余数作为结果:

1  a = (b × 倍数) + 余数 

当倍数取最大值的时候, 就会刚好可以容入 a 中.

把 9 和 4 代入等式中, 我们得 1:

1  9 = (4 × 2) + 1 

同样的方法, 我来们计算 -9 % 4 :

1 -9 % 4   // 等于 -1 

把 -9 和 4 代入等式, -2 是取到的最大整数:

1 -9 = (4 × -2) + -1 

余数是 -1.

在对负数 -b 求余时, -b的符号会被忽略. 这意味着 a % b 和 a % -b的结果是相同的.

浮点数求余计算

不同于C和Objective-C, Swift中是可以对浮点数进行求余的.

1  8 % 2.5 // 等于 0.5 

这个例子中, 8除于2.5等于3余0.5, 所以结果是0.5.

自增和自增运算

和C一样, Swift也提供了方便对变量本身加1或减1的自增 ++ 和自减 -- 的运算符. 其操作对象可以是整形和浮点型。 ‌

1 var i = 0
2 ++i      // 现在 i = 1 

每调用一次 ++i, i 的值就会加1. 实际上, ++i 是 i = i + 1 的简写, 而 --i 是 i = i - 1的简写.

++ 和 --既是前置又是后置运算. ++i, i++, --i 和 i-- 都是有效的写法.

我们需要注意的是这些运算符修改了 i 后有一个返回值. 如果你只想修改 i 的值, 那你就可以忽略这个返回值. 但如果你想使用返回值, 你就需要留意前置和后置操作的返回值是不同的.

当 ++ 前置的时候, 先自増再返回.

当 ++ 后置的时候, 先返回再自增.

不懂? 我们看例子:

1 var a = 0
2 let b = ++a // a 和 b 现在都是 1
3 let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1

上述例子, let b = ++a, 先把 a 加1了再返回 a 的值. 所以 a 和 b 都是新值 1.

而 let c = a++, 是先返回了 a 的值, 然后 a 才加1. 所以 c 得到了 a 的旧值1, 而 a 加1后变成2.

除非你需要使用 i++ 的特性, 不然推荐你使用 ++i 和 --i, 因为先修改后返回这样的行为更符合我们的逻辑.

单目负号

数值的正负号可以使用前缀 - (即单目负号) 来切换:

1 let three = 3
2 let minusThree = -three       // minusThree 等于 -3
3 let plusThree = -minusThree   // plusThree 等于 3, 或 "负负3" 

单目负号写在操作数之前, 中间没有空格.

单目正号

单目正号 + 不做任何改变地返回操作数的值.

1 let minusSix = -6
2 let alsoMinusSix = +minusSix  // alsoMinusSix 等于 -6 

虽然单目 + 做无用功, 但当你在使用单目负号来表达负数时, 你可以使用单目正号来表达正数, 如此你的代码会具有对称美.

复合赋值

如同强大的C语言, Swift也提供把其他运算符和赋值运算 = 组合的复合赋值运算符, 加赋运算 += 是其中一个例子:

1 var a = 1
2 a += 2 // a 现在是 3 

表达式 a += 2 是 a = a + 2 的简写, 一个加赋运算就把加法和赋值两件事完成了.

注意:复合赋值运算没有返回值, let b = a += 2 这类代码是错误. 这不同于上面提到的自增和自减运算符.

表达式里有复合运算符的完整列表. ‌

比较运算

所有标准C中的比较运算都可以在Swift中使用.

等于 a == b

不等于 a != b

大于 a > b

小于 a < b

大于等于 a >= b

小于等于 a <= b

注意: Swift也提供恒等 === 和不恒等 !== 这两个比较符来判断两个对象是否引用同一个对象实例. 更多细节在 类与结构.

每个比较运算都返回了一个标识表达式是否成立的布尔值:

1 1 == 1   // true, 因为 1 等于 1
2 2 != 1   // true, 因为 2 不等于 1
3 2 > 1    // true, 因为 2 大于 1
4 1 < 2    // true, 因为 1 小于2
5 1 >= 1   // true, 因为 1 大于等于 1
6 2 <= 1   // false, 因为 2 并不小于等于 1 

比较运算多用于条件语句, 如 if 条件:

1 let name = "world"
2 if name == "world" {
3     println("hello, world")
4 } else {
5     println("对不起, \(name), 我不认识你!")
6 }
7 // 输出 "hello, world", 因为 `name` 就是等于 "world" 

关于 if 语句, 请看 控制流.

三目条件运算

三目条件运算的特殊在于它是有三个操作数的运算符, 它的原型是 问题 ? 答案1 : 答案2. 它简洁地表达根据 问题 成立与否作出二选一的操作. 如果 问题 成立, 返回 答案1 的结果; 如果不成立, 返回 答案2 的结果.

使用三目条件运算简化了以下代码:

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

这里有个计算表格行高的例子. 如果有表头, 那行高应比内容高度要高出50像素; 如果没有表头, 只需高出20像素.

1 let contentHeight = 40
2 let hasHeader = true
3 let rowHeight = contentHeight + (hasHeader ? 50 : 20)
4 // rowHeight 现在是 90 

这样写会比下面的代码简洁:

1 let contentHeight = 40
2 let hasHeader = true
3 var rowHeight = contentHeight
4 if hasHeader {
5     rowHeight = rowHeight + 50
6 } else {
7     rowHeight = rowHeight + 20
8 }
9 // rowHeight 现在是 90 

第一段代码例子使用了三目条件运算, 所以一行代码就能让我们得到正确答案. 这比第二段代码简洁得多, 无需将 rowHeight 定义成变量, 因为它的值无需在 if 语句中改变.

三目条件运算提供有效率且便捷的方式来表达二选一的选择. 需要注意的事, 过度使用三目条件运算就会由简洁的代码变成难懂的代码. 我们应避免在一个组合语句使用多个三目条件运算符.

区间运算符

Swift提供了两个方便表达一个区间的值的运算符.

闭区间运算符

闭区间运算符 a...b 定义一个包含从 a 到 b (包括 a 和 b)的所有值的区间. ‌ 闭区间运算符在迭代一个区间的所有值时是非常有用的, 如在 for-in 循环中:

1 for index in 1...5 {
2   println("\(index) * 5 = \(index * 5)")
3 }
4 // 1 * 5 = 5
5 // 2 * 5 = 10
6 // 3 * 5 = 15
7 // 4 * 5 = 20
8 // 5 * 5 = 25 

关于 for-in, 请看 控制流.

半闭区间

半闭区间 a..b 定义一个从 a 到 b 但不包括 b 的区间. 之所以称为半闭区间, 是因为该区间包含第一个值而不包括最后的值.

半闭区间的实用性在于当你使用一个0始的列表(如数组)时, 非常方便地从0数到列表的长度.

1 let names = ["Anna", "Alex", "Brian", "Jack"]
2 let count = names.count
3 for i in 0..count {
4     println("第 \(i + 1) 个人叫 \(names[i])")
5 }
6 // 第 1 个人叫 Anna
7 // 第 2 个人叫 Alex
8 // 第 3 个人叫 Brian
9 // 第 4 个人叫 Jack 

注意: 数组有4个元素, 但 0..count 只数到 3 (最后一个元素的下标), 因为它是半闭区间. 关于数组, 请查阅 数组.

逻辑运算

逻辑运算的操作对象是逻辑布尔值. Swift支持基于C语言的三个标准逻辑运算.

逻辑非 !a

逻辑与 a && b

逻辑或 a || b

逻辑非

逻辑非运算 !a 对一个布尔值取反, 使得 true 变 false, false 变 true.

它是一个前置运算符, 需出现在操作数之前, 且不加空格. 读作 非 a, 然后我们看以下例子:

1 let allowedEntry = false
2 if !allowedEntry {
3     println("ACCESS DENIED")
4 }
5 // prints "ACCESS DENIED" 

if !allowedEntry语句可以读作 "如果 非 alowed entry.", 接下一行代码只有在如果 "非 allow entry" 为 true, 即 allowEntry 为 false 时被执行.

在示例代码中, 小心地选择布尔常量或变量有助于代码的可读性, 并且避免使用双重逻辑非运算, 或混乱的逻辑语句.

逻辑与

逻辑与 a && b 表达了只有 a 和 b 的值都为 true 时, 整个表达式的值才会是 true .

只要任意一个值为 false, 整个表达式的值就为 false. 事实上, 如果第一个值为 false, 那么是不去计算第二个值的, 因为它已经不可能影响整个表达式的结果了. 这被称做 "短路计算".

以下例子, 只有两个值都为值的时候才允许进入:

1 let enteredDoorCode = true
2 let passedRetinaScan = false
3 if enteredDoorCode && passedRetinaScan {
4     println("Welcome!")
5 } else {
6     println("ACCESS DENIED")
7 }
8 // 输出 "ACCESS DENIED 

逻辑或

逻辑或 a || b 是一个由两个连续的 | 组成的中置运算符. 它表示了两个逻辑表达式的其中一个为 true, 整个表达式就为 true.

同逻辑与运算类似, 逻辑或也是"短路计算"的, 当左端的表达式为 true 时, 将不计算右边的表达式了, 因为它不可能改变整个表达式的值了.

以下示例代码中, 第一个布尔值 hasDoorKey 为 false, 但第二个值 knowsOverridePassword 为 true, 所以整个表达是 true, 于是允许进入:

1 let hasDoorKey = false
2 let knowsOverridePassword = true
3 if hasDoorKey || knowsOverridePassword {
4     println("Welcome!")
5 } else {
6     println("ACCESS DENIED")
7 }
8 // 输出 "Welcome!" 

组合逻辑

我们可以组合多个逻辑运算来表达一个复合逻辑:

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

这个例子使用了含多个 && 和 || 的复合逻辑. 但无论怎样, && 和 || 始终只能操作两个值. 所以这实际是三个简单逻辑连续操作的结果. 我们来解读一下:

如果我们输入了正确的密码并通过了视网膜扫描; 或者我们有一把有效的钥匙; 又或者我们知道紧急情况下重置的密码, 我们就能把门打开进入.

前两种情况, 我们都不满足, 所以前两个简单逻辑的结果是 false, 但是我们是知道紧急情况下重置的密码的, 所以整个复杂表达式的值还是 true.

使用括号来明确优先级

为了一个复杂表达式更容易读懂, 在合适的地方使用括号来明确优先级是很有效的, 虽然它并非必要的. 在上个关于门的权限的例子中, 我们给第一个部分加个括号, 使用它看起来逻辑更明确.

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

这括号使得前两个值被看成整个逻辑表达中独立的一个部分. 虽然有括号和没括号的输出结果是一样的, 但对于读代码的人来说有括号的代码更清晰.

可读性比简洁性更重要, 请在可以让你代码变清晰地地方加个括号吧!

The Swift Programming Language-官方教程精译Swift(3)基本运算符

时间: 2024-09-30 15:17:39

The Swift Programming Language-官方教程精译Swift(3)基本运算符的相关文章

The Swift Programming Language-官方教程精译Swift(6)控制流--Control Flow

Swift提供了类似C语言的流程控制结构,包括可以多次执行任务的for和while循环,基于特定条件选择执行不同代码分支的if和switch语句,还有控制流程跳转到其他代码的break和continue语句. 除了C里面传统的 for 条件递增循环,Swift 还增加了 for-in 循环,用来更简单地遍历数组(array),字典(dictionary),范围(range),字符串(string)和其他序列类型. Swift 的 switch 语句比 C 语言中更加强大.在 C 语言中,如果某个

The Swift Programming Language-官方教程精译Swift(8)闭包 -- Closures

闭包是功能性自包含模块,可以在代码中被传递和使用. Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似. 闭包可以捕获和存储其所在上下文中任意常量和变量的引用. 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包.Swift会为您管理在捕获过程中涉及到的内存操作.  注意:如果您不熟悉 捕获 (capturing) 这个概念也不用担心,后面会详细对其进行介绍. 在 函数 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采

The Swift Programming Language-官方教程精译Swift(5)集合类型 -- Collection Types

Swift语言提供经典的数组和字典两种集合类型来存储集合数据.数组用来按顺序存储相同类型的数据.字典虽然无序存储相同类型数据值但是需要由独有的标识符引用和寻址(就是键值对). Swift语言里的数组和字典中存储的数据值类型必须明确. 这意味着我们不能把不正确的数据类型插入其中. 同时这也说明我们完全可以对获取出的值类型非常自信. Swift对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚,也让我们在开发中可以早早地找到任何的类型不匹配错误. 注意: Swift的数组结构在被声明成常

The Swift Programming Language-官方教程精译Swift(1)小试牛刀

通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”.在 Swift 中,可以用一行代码实现: 1 println("hello, world") 如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序.你不需要为了输入输出或者字符串处理导入一个单独的库.全局作用域中的代码会被自动当做程序的入口点,所以你也不需要main函数.你同样不需要在每个语句结尾写上分号. 这个教程会通过一系列编程例

The Swift Programming Language-官方教程精译Swift(2)基础知识

Swift 的类型是在 C 和 Objective-C 的基础上提出的,Int是整型:Double和Float是浮点型:Bool是布尔型:String是字符串.Swift 还有两个有用的集合类型,Array和Dictionary,请参考集合类型. 就像 C 语言一样,Swift 使用变量来进行存储并通过变量名来关联值.在 Swift 中,值不可变的变量有着广泛的应用,它们就是常量,而且比 C 语言的常量更强大.在 Swift 中,如果你要处理的值不需要改变,那使用常量可以让你的代码更加安全并且更

The Swift Programming Language-官方教程精译Swift(4)字符串和字符

String 是一个有序的字符集合,例如 "hello, world", "albatross".Swift 字符串通过 String 类型来表示,也可以表示为 Character 类型值的集合. Swift 的 String 和 Character 类型提供了一个快速的,兼容 Unicode 的方式来处理代码中的文本信息.创建和操作字符串的语法与 C的操作方式相似,轻量并且易读.字符串连接操作只需要简单地通过 + 号将两个字符串相连即可.与 Swift 中其他值一

The Swift Programming Language-官方教程精译Swift(9) 枚举-- --Enumerations

枚举定义了一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值. 如果你熟悉 C 语言,你就会知道,在 C 语言中枚举指定相关名称为一组整型值.Swift 中的枚举更加灵活,不必给每一个枚举成员(enumeration member)提供一个值.如果一个值(被认为是“原始”值)被提供给每个枚举成员,则该值可以是一个字符串,一个字符,或是一个整型值或浮点值. 此外,枚举成员可以指定任何类型的关联值存储到枚举成员值中,就像其他语言中的联合体(unions)和变体(varian

[精校版]The Swift Programming Language

通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”.在 Swift 中,可以用一行代码实现: println("hello, world") 如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序.你不需要为了输入输出或者字符串处理导入一个单独的库.全局作用域中的代码会被自动当做程序的入口点,所以你也不需要main函数.你同样不需要在每个语句结尾写上分号. 这个教程会通过一系列编程例子来

一群牛人翻译:The Swift Programming Language 中文版

无聊闲逛GIthub,看到一群牛人在github上创建了一个关于Switf的文档翻译项目 The Swift Programming Language 中文版 项目地址:中文版 Apple 官方 Swift 教程<The Swift Programming Language> 需要的小伙伴们速度去查阅. 到现在6月12日下午4:59.英文版的手册仅发布9天. star和fork的数量增长惊人 一群牛人翻译:The Swift Programming Language 中文版