原文:Swift语言指南(九)--基本运算符

运算符(operator)是用来检查,改变或合并值的一种特殊符号或短语。例如,加号运算符让两个数字相加(如:let i = 1 + 2),还有些更复杂的运算符,如逻辑与运算符(&&)(如:if enteredDoorCode && passedRetinaScan)和自增运算符(++i)(将 i 的值加 1 的便捷写法)。

Swift 支持标准C语言的大多数运算符,并且改进了一些特性以规避常见的代码错误。赋值运算符(=)是没有返回值的,这样是为了避免在使用等于运算符(==)时误用了赋值运算符(=)。算术运算符(+,-,*,/,% 等等)会侦测并阻止值溢出,可避免在运算时超出存储类型的值域范围(比实际运算结果大或小,或不精准--Joe.Huang)。如果需要支持溢出行为,可以选用 Swift 的溢出运算符,详情可见 溢出运算符(后面章节译到)。

与C语言不同的是,Swift 允许对浮点数求余(%)。Swift 还提供了C语言所没有的两个区间运算符(a..b和a...b),作为表示值域范围的便捷写法。

本章介绍 Swift 中的常用运算符。高级运算符 (后面章节译到) 一章涵盖了 Swift 中的高级运算符,并讲解了如何自定义运算符,以及让标准运算符支持自定义类型的运算。

运算符术语

运算符分为一元,二元,三元运算符:

· 一元运算符unary operator)对单个目标进行运算(如 -a)。一元运算符前缀unary prefix operator)紧跟运算目标之前(如 !b),而一元运算符后缀unary postfix operator)则紧跟运算目标之后(如 i++)。

· 二元运算符binary operator)对两个目标进行运算(如 2 + 3),它们属于中缀infix)运算符,因为(运算符号)出现在两个运算目标之间。

· 三元运算符ternary operator)对三个目标进行运算。与 C 语言一样,Swift 只有一个三元运算符:三元条件运算符( a ? b : c)。

运算符操作的值称为运算元operands)。在表达式 1 + 2 中,与值 2。

赋值运算符

赋值运算符assignment operator,a = b)用 b 的值初始化或更新 a 的值:

 let b =
 var a =
 a = b
 // a is now equal to 10
 //a现在等于10

如果赋值语句的右侧是一个包含多个值的元组,元组的元素可一次性用多个常量或变量分解提取出来(上一章讲解元组时提到过分解元组值的方法--Joe.Huang):

 let (x, y) = (, )
 // x is equal to 1, and y is equal to 2
 //x等于1,y等于2

与 C 或 Objective-C 语言的赋值运算符不同,Swift 语言的赋值运算符本身没有返回值。因此下面的语句不正确:

 if x = y {
     // this is not valid, because x = y does not return a value
     // 这是无效的,因为 x = y 不会返回一个值 (x==y才可以,--Joe.Huang)
 }

该特性可避免在使用等于运算符(==)时误用了赋值运算符(=)。通过否认 if x = y 的有效性,Swift 将帮助你规避代码中出现这样的错误。

算术运算符

Swift支持对所有数字类型使用四种标准算术运算符:

· 加:+

· 减:-

· 乘:*

· 除:/

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

与 C / Objective-C 语言的算术运算符不同,Swift 的算术运算符默认不允许值溢出。如果需要支持溢出行为,可以选用 Swift 的溢出运算符(如,a &+ b),详情可见 溢出运算符(后面章节译到)。

加号运算符也支持 String 拼接:

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

可以将两个 Character (字符,Unicode字符--Joe.Huang)值相加,或将一个 Character 值与一个 String 值相加,得到新的 String 值:

 let dog: Character = ""
 let cow: Character = ""
 let dogCow = dog + cow
 // dogCow 等于 ""

详见 字符与字符串拼接 (后面章节译到):

求余运算符

求余运算符remainder operator,a % b)求出 a 包含多少个 b,并返回剩余的值(即整除后的余数 remainder)。

注:

求余运算符(%)在其他语言中也称作求模运算符modulo operator)。但对负数的运算结果表明:Swift 语言的实现是严格的求余操作,而非求模操作。

求余运算符的原理如下。 要计算 9 % 4,首先要求出 9 里面包含多少个 4:

如图所示, 里面包含两个 ,余数是 (橙色部分)。

Swift中的写法如下:

 %   //等于 1

要求出 a % b 的结果,% 运算符会计算下面的等式,并将余数作为输出结果返回:

a = (b × some multiplier) + remainder

其中 some multipliera 中能装下 b 的最大数目。

把 和 代入等式:

 = ( × ) + 

a 为负数时,求余方法不变:

- %    // 等于 -1

把 代入等式:

- = ( × -) + -

得到的余数值为-1。

b 为负值(-b)时,b 的负号将被忽略。因此 a % ba % -b 总是返回相同的结果。

浮点数的求余计算

与 C / Objective-C 语言的余数运算符不同,Swift 的余数运算符还能对浮点数进行求余计算:

 % 2.5   // equals 0.5

上例中,8 除以 2.5 等于 3,余数为 0.5,因此余数运算符返回 Double 型的值 0.5。

自增与自减运算符

与 C 语言类似,Swift 也提供了自增运算符(++)与自减运算符(--),作为将数字变量的值加上或减去 1 的便捷写法。任何整型或浮点型的变量都可以使用这两个运算符。

 var i =
 ++i      // i 现在等于 1

每次调用 ++i 时,i 的值就会增加 1。本质上,++i 就是 i = i + 1 的便捷写法。类似地,--i 也相当于 i = i - 1

++ 与 -- 两对符号可以作为前缀或后缀运算符使用。++ii++ 均可用来将 。类似地,--i

注意,这些运算符不仅会改变 i 的值,还会返回一个值。如果你只需要将自增或自减后的值存放在 i 中,那你可以忽略运算符的返回值。但如果你确实要用到返回值,要注意前缀及后缀运算符返回值的差异,规则如下:

· 如果运算符在变量名前面,先改变它的值,再返回其值。

· 如果运算符在变量名后面,先返回原值,再改变它的值。

如例:

 var a =
 let b = ++a
 // a 和 b 现在都等于 1,即改变a的值,再返回
 let c = a++
 // a 现在等于 2, 但 c 还是自增前的值 1,即先返回的a的原值,再改变其值

在上例中,let b = ++a 先增加 a 的值。

但是,let c = a++ 先返回 a 的原值,然后 。

除非你需要利用 i++ 的这一特性,建议你在所有情况下都使用 ++i 与 --i,因为它们先修改 i 再返回修改后的值的动作更符合逻辑。

一元减号运算符

数值前加上前缀 - ,这个前缀运算符 - 就称为一元减号运算符:

 let three =
 let minusThree = -three       // minusThree 等于 -3
 let plusThree = -minusThree   // plusThree 等于 3, 或等于 "减去 minusThree"

一元减号运算符(-)紧靠所要操作的值之前,无需任何空格。

一元加号运算符

一元加号运算符(+)直接返回所操作的值,不作任何处理:

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

尽管一元加号运算符实际上不作任何运算,代码中仍然可以用它(提供语义信息,一元减号运算符表示负数,一元加号运算符表示正数--Joe.Huang)与表示负数的一元减号运算符形成对比。

复合赋值运算符

与 C 语言类似,Swift 也提供复合赋值运算符(compound assignment operator)将赋值运算符(=)与其他运算组合起来使用。例如加法赋值运算符(addition assignment operator+=):

 var a =
 a +=
 // a 等于 3

上例中的表达式 a = a + 2 简写为 a += 2,加法和赋值两项操作组合为一个单项操作,执行时非常高效。

注:

复合赋值操作没有返回值,即,你不能写:let b = a += 2,这一操作与前面所提到的自增自减操作是不同的。

复合赋值运算符的完整列表可在 表达式 一章中找到(后面章节译到)。

比较运算符

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

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

注:

Swift还提供了恒等(===)和不恒等(!==)两个鉴别运算符,你可以用它测试两个对象是否引用了同一个对象实例。更多详情请参考 类和结构 一章(后面章节译到)。

每个比较运算符都会返回一个 Bool 值,检测表达式是否成立:

  ==    // true, 因为 1 等于 1
  !=    // true, 因为 2 不等于 1
  >     // true, 因为 2 大于 1
  <     // true, 因为 1 小于 2
  >=    // true, 因为 1 大于等于 1
  <=    // false, 因为 2 大于等于 1

比较运算符常见于条件表达式中,如 if 条件句:

 let name = "world"
 if name == "world" {
     println("hello, world")
 } else {
     println("I'm sorry \(name), but I don't recognize you")
     //输出(”对不起\name,我不认识你“)
 }
 // prints "hello, world", because name is indeed equal to "world"
 //输出 "hello world",因为 name 确实等于"world"

if 语句的更多介绍,详见 流程控制 一章(后面章节译到)。

三元条件运算符

三元运算符是一种特殊运算符,由三个部分组成,表现形式为:question ? answer1 : answer2。它是一种求值简写:根据 question 是否成立,从两个表达式中取出一个并求值。

如果 question 成立,则计算 answer1 的结果并返回其值;否则计算 answer2 并返回其值。

三元条件运算符是如下代码的缩写:

 if question {
     answer1
 } else {
     answer2
 }

下面的例子将计算表格某行的像素高度。如果该行有表头,则行高应比内容高度高 50 个像素;如果没有表头,则只高出 20 个像素:

 let contentHeight =
 let hasHeader = true
 let rowHeight = contentHeight + (hasHeader ?  : )
 // rowHeight(行高) 等于 90

上例便是如下代码的缩写:

 let contentHeight =
 let hasHeader = true
 var rowHeight = contentHeight
 if hasHeader {
     rowHeight = rowHeight +
 } else {
     rowHeight = rowHeight +
 }
 // rowHeight(行高) 等于 90

使用三元条件运算符的例子说明,可以仅用一行代码就将行高设为正确的值。这比(不用三元运算符的)第二个例子简洁得多,并且行高(rowHeight)无需定义为变量,因为不再需要用 if 语句修改其值。

三元条件运算符提供了二选一的高效写法。但使用三元条件运算符应小心。如果过度使用,其简明性可能导致代码可读性差。应避免将多个三元条件运算符组合在同一个语句中。

区间运算符

Swift有两个区间运算法,是表示值域的简便写法。

闭区间运算符

区间运算符(a...b)定义了 ab 的区间范围,包括 a 在内。

闭区间运算符在需要遍历某区间内所有的值时很有用,如在 for-in 循环中使用:

 ... {
     println("\(index) times 5 is \(index * 5)")
     //输出("\(index)乘以 5 得 (\index * 5)")
 }
 // 1 乘以 5 得 5
 // 2 乘以 5 得 10
 // 3 乘以 5 得 15
 // 4 乘以 5 得 20
 // 5 乘以 5 得 25

for-in 语句的更多介绍,详见 流程控制 一章(后面章节译到)。

半闭区间运算符

半闭区间运算符(a..b)定义了从 ab 的区间,但 b 不包括在内。说它是半闭区间,是因为第一个值包含在区间内,但最后一个值在区间外。

半闭区间在处理从 0 开始计数的列表时有用,如遍历数组,可从 0 数到列表的长度(但不包括长度值本身):

 let names = ["Anna", "Alex", "Brian", "Jack"]
 let count = names.count
 ..count {
     println("Person \(i + 1) is called \(names[i])")
 }
 // Person 1 名字是 Anna
 // Person 2 名字是 Alex
 // Person 3 名字是 Brian
 // Person 4 名字是 Jack

注意,数组包含四个元素,但因为是半闭区间,所以 0..count 只数到 3(数组中最后一个元素的索引号)。数组更多信息详见 数组 一章(后面章节译到)。

逻辑运算符

逻辑运算符是对布尔逻辑值 truefalse 的组合操作,Swift 支持 C 及其衍生语言的三种标准逻辑运算符:

· 逻辑非(!a

· 逻辑与(a && b

· 逻辑或(a || b

逻辑非运算符

逻辑非运算符对布尔值取反,即 true 变成 falsefalse 变成true

逻辑非运算符是一个前缀运算符,紧跟在所操作值的前面,没有任何空格符。可以理解为"非",如下例:

 let allowedEntry = false
 if !allowedEntry {
     println("ACCESS DENIED")
 }
 // prints "ACCESS DENIED"
 //输出”ACCESS DENIED“

代码中的 if !allowedEntry 可以理解为“如果不允许进入”。随后的下一行代码仅当“不允许进入”成立时才会执行;即 allowedEntry 为 false 时才执行。

如上例,布尔值常量及变量的名称应谨慎选择命名,方可确保代码简明又具可读性,同时也应避免使用双重否定或引起混淆的逻辑语句。

逻辑与运算符

a && b)构造这样的逻辑表达式:运算符两侧的值均为 true,整个表达式的求值结果才为 true。

如果有一个值为 false,整个表达式便为 false。事实上,如果第一个值false,第二个值将不执行求值运算,因为无论它为何值,整个表达式的值都不可能等于 true。这也被称为短路求值short-circuit evaluation)。

下面的例子验证两个值,当两个值都为 true 时才能访问:

 let enteredDoorCode = true
 let passedRetinaScan = false
 if enteredDoorCode && passedRetinaScan {
     println("Welcome!")
 } else {
     println("ACCESS DENIED")
 }
 // prints "ACCESS DENIED"  输出"ACCESS DENIED"

逻辑或运算符

a || b)属于中缀运算符,由两个连续的竖线构成。它用来构造这样的表达式:当两个值中有一个为 true时,整个表达式为 true

与前面的逻辑与运算符一样,逻辑或运算符在检测它的两个表达式时,也使用“短路求值”法。只要逻辑或表达式左侧为 true,其右侧将不执行求值运算,因为这时右侧的值对整个表达式的结果不再有影响。

下例中,第一个 Bool 值(hasDoorKey)为 false,但第二个值(knowOverridePassword)为 true。因为有一个值为 true,所以整个表达式的求值结果也为 true,因此允许访问:

 let hasDoorKey = false
 let knowsOverridePassword = true
 if hasDoorKey || knowsOverridePassword {
     println("Welcome!")
 } else {
     println("ACCESS DENIED")
 }
 // prints "Welcome!"  输出"Welcome!"

组合使用逻辑运算符

可以将多个逻辑运算符组合起来构成一个较长的复合表达式。

 “if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
     println("Welcome!")
 } else {
     println("ACCESS DENIED")
 }
 // prints "Welcome!"  输出"Welcome!"

本例使用多个 &&|| 运算符构成一条较长的复合表达式。不过,&&|| 运算符操作的仍然是两个值,因此该组合表达式实际上是由三个较短的表达式连立而成。它可以这样理解:

如果我们输入了正确的门禁密码、并且通过了视网膜扫描;或者如果我们有门钥匙;或者如果我们知道紧急的备用密码,则允许访问。

根据 enteredDoorCodepassedRetinaScanhasDoorKey 三个常量推算,前两个小表达式的值均为 false。不过我们知道紧急的备用密码(knowsOverridePassword 为 true),因此整个复合表达式的求值结果仍然为 true


显式括号

有时(从语法来看)括号并不是必需的,但加上括号却很有用,它可以让复杂表达式的易于阅读。 在上例中,为组合表达式的第一部分加上括号,可使其意图更明显:

 if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
     println("Welcome!")
 } else {
     println("ACCESS DENIED")
 }
 // prints "Welcome!"  //输出"Welcome!"

括号将前两个值与其他值分隔开来,使其作为整体逻辑中的一种可选状态的意思更加明显。组合表达式的结果不会改变,但对读者而言,整体意图更加清晰。可读性总是优先于简洁性;应尽可能在合适的地方使用括号,使你的逻辑更加明晰。

谢谢,Swifter-QQ群:362232993,同好者进~

Fork:https://github.com/Joejo/Swift-lesson-for-chinese

Swift语言指南(九)--基本运算符的更多相关文章

  1. Swift语言指南(七)--语言基础之布尔值和类型别名

    原文:Swift语言指南(七)--语言基础之布尔值和类型别名 布尔值 Swift有一个基本布尔类型,叫做布尔(bool),布尔值又称逻辑值(logical),因为它只能为真(true)或假(false ...

  2. Swift语言指南(十)--字符串与字符

    原文:Swift语言指南(十)--字符串与字符 字符串是一段字符的有序集合,如"hellow,world"或"信天翁".Swift 中的字符串由 String ...

  3. Swift语言指南(四)--类型安全和类型推断

    原文:Swift语言指南(四)--类型安全和类型推断 Swift是一门类型安全语言,类型安全语言需要代码里值的类型非常明确.如果你的代码中有部分值需要String类型,你就不能错误地传递Int. 鉴于 ...

  4. Swift语言指南(五)--数字字面量和数字类型转换

    原文:Swift语言指南(五)--数字字面量和数字类型转换 数字字面量 整数字面量写法如下: · 十进制数,无前缀 · 二进制数,以 0b 为前缀 · 八进制数,以 0o 为前缀 · 十六进制数,以 ...

  5. Swift语言指南(六)--可选值

    原文:Swift语言指南(六)--可选值 在值可能不存在的情况下使用可选值(optional), 可选值是: · 存在一个值,这个值等于 x 或 · 不存在任何值 注: 在 C 和 Objective ...

  6. Swift语言指南(二)--语言基础之注释和分号

    原文:Swift语言指南(二)--语言基础之注释和分号 注释 通过注释向自己的代码中注入不可执行的文本,作为你自己的笔记或提示.Swift编译器运行时会忽略注释. Swift的注释与C语言极其相似,单 ...

  7. Swift语言指南(三)--语言基础之整数和浮点数

    原文:Swift语言指南(三)--语言基础之整数和浮点数 整数 整数指没有小数的整数,如42,-23.整数可以是有符号的(正数,零,负数),也可以是无符号的(正数,零). Swift提供了8,16,3 ...

  8. Swift语言指南(一)--语言基础之常量和变量

    原文:Swift语言指南(一)--语言基础之常量和变量 Swift 是开发 iOS 及 OS X 应用的一门新编程语言,然而,它的开发体验与 C 或 Objective-C 有很多相似之处. Swif ...

  9. Swift语言指南(八)--语言基础之元组

    原文:Swift语言指南(八)--语言基础之元组 元组 元组(Tuples)将多个值组合为一个复合值.元组内的值可以是任何类型,各个元素不需要为相同类型(各个元素之间类型独立,互不干扰--Joe.Hu ...

随机推荐

  1. 未能加载文件或程序集“Microsoft.SQLServer.DTSRuntimeWrap”或它的某一个依赖项。试图加载格式不正确的程序。

    只要将应用程序池中的是否启用32位应用程序改为支持就可以了

  2. Cdnbes负载均衡的权重用法解释

    (1)相同域名添加两条记录,解析不同的ip,可以设置权重,比如权重2,就意思占百分之20 ,数字越大,优先级越大 (2)这个hash 如果用户访问的源是挂掉的.会去第二个源

  3. Netty学习二:Java IO与序列化

    1 Java IO 1.1 Java IO 1.1.1 IO IO,即输入(Input)输出(Output)的简写,是描述计算机软硬件对二进制数据的传输.读写等操作的统称. 按照软硬件可分为: 磁盘I ...

  4. Testing - 测试基础 - 流程

    测试存在于各个阶段: 需求测试--->单元测试--->集成测试--->系统测试--->性能测试--->用户测试--->回归测试 需求测试 完整性&正确性 一 ...

  5. Html5拖拽复制

    拖拽是一种常见的特性,即抓取对象以后拖到另一个位置. 在 HTML5 中,拖拽是标准的一部分,任何元素都能够拖拽. Html5拖拽非常常见的一个功能,但是大部分拖拽的案例都是一个剪切的过程, 项目中需 ...

  6. jquery笔记(遍历)

    祖先: $("selector").parent().css():返回被选元素的直接父元素,并调用css方法. $("selector").parents(). ...

  7. linux中用shell获取时间,日期

    linux中用shell获取昨天.明天或多天前的日期:在Linux中对man date -d 参数说的比较模糊,以下举例进一步说明:# -d, --date=STRING display time d ...

  8. Linux下安装软件的一般步骤

    目录 一.解析Linux应用软件安装包 二.了解包里的内容 三.搞定使用tar打包的应用软件 四.搞定使用rpm打包的应用软件 五.搞定使用deb打包的应用程序 一.解析Linux应用软件安装包(回目 ...

  9. IntelliJ IDEA使用SSH功能

    Tools→Start SSH session... 选择Edit credentials... 输入SSH登录信息即可 输入SSH登录信息,Port默认为22 来自为知笔记(Wiz)

  10. java 复习

    整型: byte 1 short 2 int 4 long 80b1001 1_233_32 1341414141414Ljava 没有无符号类型浮点型:float 4 double 812.2f 无 ...