操作符是用于检测、更改或者组合值的特殊符号或短语。例如,加法操作符 (+) 将两个数字加到一起 (如 let i = 1 + 2)。更复杂的例子包括逻辑与操作符 && (如 if enteredDoorCode && passedRetinaScan) 和自增操作符 ++i,就是把 i 的值加1的快捷方式。

Swift 支持大多数标准的C 操作符并且改善了几项功能以消除常见的编码错误。赋值操作符 (=) 不返回值,是为了防止想用等于操作符(==)时不小心用成了赋值操作符。算数运算符 (+,-,*,/,% 等等) 检测并禁止值溢出,以免运算时得出的结果大于或小于类型允许的范围。你可以用 Swift 的溢出运算符来做溢出操作,详情见《溢出操作符》一节。

不像C,Swift 可以对浮点数进行取余操作 (%) 。 Swift 还提供两个范围操作符 (a..<b 和 a…b) ,这在C里是没有的,用来表示一个范围的值。

这一章讲述 Swift 里的常用操作符。《高级操作符》一节涵盖了Swift 的高级操作符,讲述了如何自定义操作符以及如何实现自定义类型的标准操作符。

术语

操作符分一元、二元和三元:

一元操作符操作于一个单一目标(如 -a)。一元前缀操作符在它们的目标之前紧跟出现(如 !b),一元后缀操作符在它们的目标之后紧跟出现(如 i++)。
二元操作符操作于两个目标(如 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)
// x 等于 1,而且 y 等于 2

不像 C 和 Objective-C 里的赋值操作符,Swift 里的赋值操作符自身并不返回值。下面的语句是不行的:

if x = y {
    // 这是无效的,因为 x = y 并不返回值
}

这个特性防止了赋值操作符 (=) 被误用作等于操作符 (==) 。Swift 帮你避免 if x = y 这些错误在代码里出现。

算术运算符

Swift 对数字类型支持四种标准的算术运算符:

加 (+)
减 (-)
乘 (*)
除 (/)

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

不像 C 和 Objective-C 里的算术运算符,Swift 算术运算符默认不允许值溢出。你可以用 Swift 的溢出操作符(如 a &+ b)来选择值溢出操作。更多内容见《溢出操作符》一节。

加操作符还支持字符串连接:

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

取余操作符

取余操作符 (a % b) 计算的是 a 是 b 的几个倍数,并返回剩余的部分 (就是余数)。

注意

取余操作符 (%) 在其它语言里也称为取模操作符。不过,在Swift 里对负数的操作,严格来说是取余而不是取模。

这是取余操作符如何工作的例子。要计算 9 % 4,先算出9最多可以包括多少个4:

9里最多有两个4,余数是1 (上面的橙色部分).

Swift 里,这个可以写作:

9 % 4    // 等于 1

要得出 a % b 的答案, % 操作符计算以下等式并返回 remainder 作为它的输出:

a = (b × some multiplier) + remainder

some multiplier 是 a 所能容纳的b的最大倍数。

把9和4插入这个等式得出:

9 = (4 × 2) + 1

计算负数a的值也是一样的方法:

-9 % 4   // 等于 -1

把 -9 和 4 插入等式得出:

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

得出值为 -1。

b 的负数值负号会被忽略掉。这就是说 a % b 和 a % -b 都是得出一样的答案。

浮点取余计算

不像 C 和 Objective-C 的取余操作符,Swift 的取余操作符还可以计算浮点数:

8 % 2.5   // equals 0.5

在这个例子里,8 除以 2.5 等于 3,余数为 0.5,因此取余操作符返回一个 Double 值 0.5。

自增与自减操作符

像 C 一样, Swift 提供了一个自增操作符 (++) 和一个自减操作符 (- -) 表示把一个数字变量加1或减1。你可以把这两个操作符用于任何整型或浮点型变量。

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

每一次调用 ++i,i 的值都会加1。本质上来说, ++i 是 i = i + 1 的缩写。同样, - -i 是 i = i - 1的缩写。

++ 和 - - 符号既可以用于前缀,也可以用于后缀。 ++i 和 i++ 都可以把 i 的值增加1。同样, - -i 和 i- - 都可以把 i 的值减1。

注意这两个操作符在修改i的同时也会返回一个值。如果你仅仅是想增加或减少 i 的值,可以不管返回值。不过,如果确实要用返回值,前缀和后缀的使用就不一样了,根据以下规则:

如果操作符写在变量前,那么先加1或减1再返回值。
如果操作符写在变量后,那么先返回值再加1或减1。
例如:

var a = 0
let b = ++a
// a 和 b 现在都等于 1
let c = a++
// a 现在等于 2,但 c 被设为加之前的值 1

在上例中, let b = ++a 在返回值前增加 a 的值。这就是为什么 a 和 b 都等于新的值 1。

但是,let c = a++ 在返回值以后再增加 a 的值。这就是说 c 得到了旧的值 1,而 a 更改为等于2。

除非需要特别使用 i++,否则推荐你都用 ++i 和 –i ,因为这个更符合修改 i 和返回结果的典型预期行为。

一元减操作符

数字值的符号可以用前缀 - 进行切换,也就是一元减操作符:

let three = 3
let minusThree = -three       // minusThree 等于 -3
let plusThree = -minusThree   // plusThree 等于 3,或者 "负 负 三"

一元减操作符 (-) 直接加在要操作的值之前,不加任何空格。

一元加操作符

一元加操作符 (+) 只是简单地返回所操作的值,不作任何改变:

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

虽然一元加操作符实际上不干任何事,但是在既有负数又有正数的时候可以让你的代码看起来更对称一点。

复合赋值操作符

像 C 那样,Swift 也提供复合赋值操作符,将复制符 (=) 和其它操作结合起来。一个例子就是加赋值操作符 (+=):

var a = 1
a += 2 // a 现在等于 3

表达式 a += 2 是 a = a + 2 的缩写。加和赋值结合到一个操作符可以同时执行两个操作。

注意

复合操作符不返回值。不能这么写 let b = a += 2。这个和上面提到的加和减操作符不同。

《表达式》一节里有全部的复合赋值操作符介绍。

比较操作符

Swift 支持所有标准的 C 比较操作符:

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

注意

Swift 还提供了两个恒等操作符 (=== 和 !==),用来测试两个对象引用是否都引用同一个对象实例。更多信息,请参考《类与结构体》一章。

每一个比较操作符都返回一个布尔值,指示语句是否为true:

1 == 1   // true,因为 1 等于 1
2 != 1   // true,因为 2 不等于 1
2 > 1    // true,因为 2 大于 1
1 < 2    // true,因为 1 小于 2
1 >= 1   // true,因为 1 大于或等于 1
2 <= 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")
}
// 打印出 "hello,world",because name is indeed equal to "world"

要了解更多关于 if 语句的信息,参见《控制流》一章。

三元条件操作符

三元条件操作符分三个部分,形式是这样的 question ? answer1 : answer2。根据 question 是 true 还是 false 来返回那两个表达式中的一个。如果 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
var rowHeight = contentHeight
if hasHeader {
    rowHeight = rowHeight + 50
} else {
    rowHeight = rowHeight + 20
}
// rowHeight 等于 90

第一个例子里,三元条件操作符的使用表示 rowHeight 可以在一行代码里就设置上正确的值。这比第二个例子简洁得多,而且不需要把 rowHeight 定义为变量,因为它的值没有必要在 if 语句里进行更改。

三元条件操作符为决定使用两个表达式中哪一个提供了高效的缩写。但是,使用三元条件操作符的时候要小心。滥用的话,虽然简洁,但会让你的代码不好读懂。尽量避免将多个三元条件操作符合并到一条复合语句中。

Nil 合并操作符

nil 合并操作符 (a ?? b) 如果a有值则开启可选项a,否则如果a是 nil 返回 b 的值。表达式 a 都是可选类型。表达式 b 必须匹配a里存储的类型。

nil 合并运算符是以下例子的缩写:

a != nil ? a! : b

上例使用三元条件操作符并强制开启 (a!) 并当a不为nil时访问a里的值,否则返回b。 nil 合并操作符提供了封装这个条件检测和开启的一种更高雅的方式,而且形式更简洁和可读性更高。

注意

如果a的值是非nil的,b不会被求值。这就是所谓的短路求值。

以下的例子使用 nil 合并操作符从默认颜色名和可选的用户自定义颜色名之间做选择:

let defaultColorName = "red"
var userDefinedColorName: String?   // 默认为 nil

var colorNametoUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 是 nil,所以 colorNametoUse 被设置为默认的 "red"

userDefinedColorName 变量被定义为一个可选的 String ,默认值为 nil 。因为 userDefinedColorName 是一个可选类型,你可以用 nil 合并操作符来得到它的值。在上例中,操作符用来检测名为 colorNametoUse 的 String 的初始值。由于 userDefinedColorName 是 nil,所以表达式 userDefinedColorName ?? defaultColorName 返回 defaultColorName 的值 “red”。

如果你把一个非nil的值设置给 userDefinedColorName 并执行 nil 合并操作符再次检测的话,那么 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 {
    println("\(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。

半开范围特别适用于从0开始的列表,如数组,一直数到(但不包括)列表的长度:

let names = ["Anna","Alex","Brian","Jack"]
let count = names.count
for i in 0..<count {
    println("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 (就是数组的最后一个索引),因为它是一个半开范围。关于数组的更多信息,参见《数组》一节。

逻辑操作符

逻辑操作符用于修改或合并布尔逻辑值true和false。Swift 支持基于C语言的三种标准的逻辑操作符:

逻辑否 (!a)
逻辑与 (a && b)
逻辑或 (a || b)

逻辑否操作符

逻辑否操作符 (!a) 将一个布尔值取反操作,true变false,false变true。

逻辑否操作符是一个前缀操作符,在其操作的值之前立即出现,没有空格。它可以读作 “不是 a”,如下例所示:

let allowedEntry = false
if !allowedEntry {
    println("ACCESS DENIED")
}
// 打印出 "ACCESS DENIED"

短语 if !allowedEntry 可以读作 “如果不允许进入” 。如果“不允许进入”是true,后续代码才会执行;也就是如果 allowedEntry 是 false。

正如在这个例子里所说,谨慎使用布尔常量和变量名可以帮助保持代码的可读性和简洁性,而避免双重否定或混乱的逻辑语句。

逻辑与操作符

逻辑与操作符 (a && b) 创建逻辑表达式,只有两个值都是true时整个表达式的值才为true。

如果其中一个值是false,整个表达式也会是false。实际上,第一个值是false的话,都不会再看第二个值,因为不可能会使整个表达式等于true的。这就是所谓的短路取值。

这个例子检测两个Bool 值,并且只有两个值都是true的时候才允许访问:

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

逻辑或操作

逻辑或操作 (a || b) 是一个中缀操作符,位于两个相邻的字符之间。用它来创建的表达式只要其中一个值为true,那整个表达式的值都为true。

如上面的逻辑与操作符一样,逻辑或操作符也使用短路取值。如果逻辑与左边的表达式是true,右边的部分就不用看了,因为不管怎样都不会改变整个表达式的输出。

在下面的例子中,第一个Bool值I (hasDoorKey) 是 false,不过第二个值 (kNowsOverridePassword) 是 true。由于其中一个值是true,所以整个表达式的值就是true,允许访问:

let hasDoorKey = false
let kNowsOverridePassword = true
if hasDoorKey || kNowsOverridePassword {
    println("Welcome!")
} else {
    println("ACCESS DENIED")
}
// 打印出 "Welcome!"

逻辑操作符的结合

你可以将多个逻辑操作符结合起来以创建更长的复合表达式:

if enteredDoorCode && passedRetinaScan || hasDoorKey || kNowsOverridePassword {
    println("Welcome!")
} else {
    println("ACCESS DENIED")
}
// 打印出 "Welcome!"

这个例子使用了多个 && 和 || 操作符来创建一个更长的复合表达式。然而, && 和 || 操作符仍然只操作与两个值,所以这其实是三个更小的表达式串在一起。这个例子可以读作:

如果我们进入了正确的门并通过了视网膜扫描,或者我们有一把有效的门钥匙,或者我们知道紧急替代密码,那就可以允许访问。

基于 enteredDoorCode,passedRetinaScan,和 hasDoorKey 的值,头两个小表达式是false。不过,知道了紧急替代密码,所以整个复合表达式仍然为true。

显示的括号

有时候加上括号也是很有用的,虽然比不是严格要求必须要有,但可以使复杂的表达式更容易读懂。在上面的门禁例子里,在复合表达式的第一部分加上括号就很有用了:

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || kNowsOverridePassword {
    println("Welcome!")
} else {
    println("ACCESS DENIED")
}
// 打印出 "Welcome!"

加了括号就很明显的能看出前两个值是作为整个逻辑的一个独立部分的。复合表达式的输出并没改变,但整个表达式的意图更容易读懂了。相比简洁性,可读性更受青睐;用括号就可以让你代码的意思更明了。

Swift语言指南二基础操作符的更多相关文章

  1. ios – Swift相当于`[NSDictionary initWithObjects:forKeys:]`

    Swift的原生字典是否与[NSDictionaryinitWithObjects:forKeys:]相当?假设我有两个带键和值的数组,并希望将它们放在字典中.在Objective-C中,我这样做:当然我可以通过两个数组迭代一个计数器,使用vardict:[String:Int]并逐步添加东西.但这似乎不是一个好的解决方案.使用zip和enumerate可能是同时迭代两者的更好方法.然而,这种方法

  2. ios – 无法识别的选择器发送到实例NSTimer Swift

    解决方法让updateTime成为一个类方法.如果它是在一个纯粹的Swift类中,你需要在@objc前面说明该方法的声明,如:

  3. ios – 在Swift中获取Cocoa Touch Framework项目版本字符串

    有谁知道这是否是我的项目设置中的缺陷,Xcode中的一个错误,或者是否有一种方法可以将Swift中的框架版本作为String或数组获取,这样我可以提供比major.minor更精细的版本控制?

  4. ios – 搜索数组swift中的对象

    我正在尝试使用UISearchController创建搜索功能.但是,我似乎无法使其与我的团队对象一起工作.我首先创建了一个包含id,name和shortname的TeamObject.然后我从一个url中检索teamData,并将TeamObjects添加到一个填充到tableView中的数组中.这个tableView包含一个searchController,它假设过滤数据,但没有任何反应.阵列

  5. ios – 类型推断(自动类型检测)如何在swift中工作?

    LLVM如何检测变量是一个字符串?

  6. ios – Swift可选项:语言问题,还是做错了什么?

    应该有可选的类型;type是但是,如果我这样做,它的工作原理:它似乎是基本的替代,但我可能会遗漏一些语言的细微差别.谁能对此有所了解?之后就像暧昧一样,更多,这是我的解决方案:这适用于所有非对象Swift对象,包括Swift字符串,数字等.感谢Viktor提醒我String不是Swift中的对象.如果您知道值的类型,您可以替换任何?使用适当的可选类型,如String?

  7. ios – 覆盖Swift中的超类委托

    我正在开发一个包含两个UIViews的Swift(v1.2)项目.MyView和MyViewSubclass.MyView有一个委托,我想在MyViewSubclass中覆盖它作为一个子协议,类似于UITableViews有一个UITableViewDelegate,它也符合超级uiscrollviewdelegate.我的第一个想法是覆盖超类属性,但这会导致编译器错误,因为子类不能覆盖具有不同类

  8. ios – Swift – 使用字典数组从字典访问数据时出错

    我有一个非常简单的例子,说明我想做什么基本上,我有一个字典,其值包含[String:String]字典数组.我把数据填入其中,但当我去访问数据时,我收到此错误:Cannotsubscriptavalueoftype‘[([String:String])]?’withanindexoftype‘Int’请让我知道我做错了什么.解决方法您的常量数组是可选的.订阅字典总是返回一个可选项.你必须打开它.更

  9. ios – 在Swift中使用“Map”创建两个数组的超集

    假设我有两个数组:我想组合两个数组,以便我得到一个输出我该怎么做呢?

  10. 模糊地使用’下标’ – ios 9 Swift 2.0

    我在xcode7.0上使用Swift2.0编写iosapp.在更新到最新版本的xCode7.1之前,完全相同的代码完全正常更新后,我收到此错误:Ambiguoususeof‘subscript’在这些方面:这是全班:Theoriginallibrary解决方法编译器不知道self.itemAttributes[indexPath.section]返回的内容,因为它定义为NSMutableArray

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部