基本运算符
今天我们来看看Swift的基本运算符。
Swift支持大部分标准C语言的运算符,且改进许多特性来减少常规编码错误。如赋值符(=
)不返回值,以防止把想要判断相等运算符(==
)的地方写成赋值符导致的错误。算术运算符(+
,-
,*
,/
,%
等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用Swift的溢出运算符来实现溢出。
不同于C语言,Swift允许对浮点数进行取余运算(%
),还提供了表达两数之间的的值得区间运算符(a..<b
和a...b
)。
术语
运算符分为一元、二元和三元运算符。受运算符影响的值叫操作数。
- 一元运算符对单一操作对象操作(如
-a
)。一元运算符分前置运算符和后置运算符,前置运算符需紧跟在操作对象之前(如!b
),后置运算符需紧跟在操作对象之后(如i++
)。 - 二元运算符操作两个操作对象(如
2 + 3
),是中置的,因为它们出现在两个操作对象之间。 - 三元运算符操作三个操作对象,和C语言一样,Swift只有一个三元运算符,就是三目运算符(
a ? b : c
)。
赋值运算符
即a = b
。如果赋值的右边是一个多元组,它的元素可以马上被分解成多个常量或变量。
let a = 100
var b = 0
b = a
let (c,d) = (1,2)
与C语言和Objective-C不同,Swift的赋值操作并不返回任何值。这个特性使得你无法把==
错写成=
。
var a = 1
var b = 2
/*if a = b { // error: type '()' does not conform to protocol 'BooleanType'
print("a == b.")
}*/
算术运算符
基本的算术运算符有+
、-
、*
和/
。与C语言和Objective-C不同的是,Swift默认情况下不允许在数值运算中出现溢出情况。但是你可以使用Swift的溢出运算符来实现溢出运算(如a &+ b
)。此外,加法运算符也可用于String
的拼接。
print(3 + 2)
print(3 - 2)
print(3 * 2)
print(3 / 2) // 1
print(3 / 2.0) // 1.5
print("111" + "222") // 111222
var a:Int8 = 100
var b:Int8 = 28
var c:Int8 = 0
var d:Int8 = 0
// c = a + b // Execution was interrupted,reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP,subcode=0x0)
print(c)
d = a &+ b
print(d) // -128
求余运算符
求余运算(a % b
)是计算b
的多少倍刚刚好可以容入a
,返回多出来的那部分(余数)。求余运算(%
)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,”求余”比”取模”更合适些。在对负数b
求余时,b
的符号会被忽略。这意味着a % b
和a % -b
的结果是相同的。
print(9 % 4) // 1
print(-9 % 4) // -1
print(-9 % -4) // -1,后两个结果相同
浮点数求余计算
不同于C和Objective-C,Swift可以对浮点数求余。
print(8 % 2.5) // 0.5
print(8 % -2.5) // 0.5 上面两行的结果相同
print(-7 % 3.1) // -0.8
自增和自减运算
即++
和--
。其操作对象可以是整数和浮点数。++
和--
既可以用作前置运算又可以用作后置运算。需要注意的是这些运算符即可修改了i
的值也可以返回i
的值,遵循下面的原则:
- 当
++
前置时,先自增再返回 - 当
++
后置时,先返回在自增 - 当
--
前置时,先自减再返回 - 当
--
后置时,先返回在自减
var a = 0
++a
print(a) // 1
var b = -1.23
++b
print(b) // -0.23
var c = 1
let d = ++c
print(c) // 2
print(d) // 2
let e = c++
print(c) // 3
print(e) // 2
除非你需要使用i++
的特性,不然推荐你使用++i
和--i
,因为先修改后返回这样的行为更符合我们的逻辑。
一元负号运算符
数值的正负号可以使用前缀-
(即一元负号)来切换。一元负号(-
)写在操作数之前,中间没有空格。
一元正号运算符
一元正号(+
)不做任何改变地返回操作数的值。虽然一元+
什么都不会改变,但当你在使用一元负号来表达负数时,你可以使用一元正号来表达正数,如此你的代码会具有对称美。
组合赋值运算符
即Compound Assignment Operators。如+=
。一个组合加运算就是把加法运算和赋值运算组合成进一个运算符里,同时完成两个运算任务。复合赋值运算没有返回值,不同于自增和自减运算符。
var a = 1
var b = 2
// b = a += 2 // error: cannot assign a value of type '()' to a value of type 'Int'
var a = 1
let b = a += 2
print(b) // (),没有错误
var c = a += 2
print(c) // (),没有错误
比较运算符
即==
、!=
、>
、<
、>=
和<=
。Swift 也提供恒等===
和不恒等!==
这两个比较符来判断两个对象是否引用同一个对象实例。比较运算符返回布尔值(true或者false)。因此多用于条件语句。
三目运算符
三目运算符(Ternary Conditional Operator)。原型是问题 ? 答案1 : 答案2
。比if语句体更简洁。
三目运算提供有效率且便捷的方式来表达二选一的选择。过度使用三目运算符会使简洁的代码变的难懂。我们应避免在一个组合语句中使用多个三目运算符。
空合运算符
Nil Coalescing Operator。空合运算符(a ?? b)
将对可选类型a
进行空判断,如果a
包含一个值就进行解封,否则就返回一个默认值b
。这个运算符需要满足有两个条件:
- 表达式a必须是Optional类型
- 默认值b的类型必须要和a存储值的类型保持一致
空合运算符是对代码a != nil ? a! : b
的简短表述。可以看出,空合运算符(??
)提供了一种更为优雅的方式去封装条件判断和解封两种行为,显得简洁以及更具可读性。
特别注意:如果a
为非空值(non-nil
),那么值b
将不会被估值(计算)。这也就是短路求值。
var a = 100
var b:Int?
var c = b ?? ++a
print(c) // 101
print(a) // 101
var d:Int = 200
c = d ?? ++a
print(c) // 200
print(a) // 101
区间运算符
Swift提供了两个简洁表达区间的值的运算符。
闭区间运算符
即a...b
。等价于数学上的[a,b]。其中必须满足b >= a。常用于for-in
循环中。
半开区间运算符
即a..<b
。等价于数学上的[a,b)。半开区间的实用性在于当你使用一个从0开始的列表(如数组)时,非常方便地从0数到列表的长度。
逻辑运算
即逻辑非(!a
)、逻辑与(&&
)和逻辑或(||
)。
逻辑非
逻辑非运算(!a
)对一个布尔值取反,使得true
变false
,false
变true
。它是一个前置运算符,需紧跟在操作数之前,且不加空格。小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。
逻辑与
逻辑与(a && b
)表达了只有a
和b
的值都为true
时,整个表达式的值才会是true
。只要任意一个值为false
,整个表达式的值就为false
。事实上,如果第一个值为false
,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做“短路计算(short-circuit evaluation)”。
逻辑或
逻辑或(a || b
)是一个由两个连续的|
组成的中置运算符。它表示了两个逻辑表达式的其中一个为true
,整个表达式就为true
。同逻辑与运算类似,逻辑或也是“短路计算”的,当左端的表达式为true
时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。
逻辑运算符组合计算
Swift逻辑操作符&&
和||
是左结合的,这意味着拥有多元逻辑操作符的复合表达式优先计算最左边的子表达式。
使用括号来明确优先级
可读性比简洁性更重要,请在可以让你代码变清晰的地方加个括号吧!