Swift 运算符

demo 地址:https://share.weiyun.com/5gIsJHA

运算符是一个符号,用于告诉编译器执行一个数学或逻辑运算。
Swift 提供了以下几种运算符:

  • 算术运算符
  • 比较运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 区间运算符
  • 其他运算符

下面将为大家详细介绍算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符及其他运算符。

算术运算符

以下表格列出了 Swift 语言支持的算术运算符,其中变量 A 为 10,变量 B 为 20:

运算符 描述 实例
+ 加号 A + B 结果为 30
减号 A - B 结果为 -10
* 乘号 A * B 结果为 200
/ 除号 B / A 结果为 2
% 求余 B % A 结果为 0

注意:swift3 中已经取消了++--

实例

以下为算术运算的简单实例:

import Cocoa

var A = 10
var B = 20

print("A + B 结果为:\(A + B)")
print("A - B 结果为:\(A - B)")
print("A * B 结果为:\(A * B)")
print("B / A 结果为:\(B / A)")
A += 1   // 类似 A++
print("A += 1 后 A 的值为 \(A)")
B -= 1   // 类似 B--
print("B -= 1 后 B 的值为 \(B)")

以上程序执行结果为:

A + B 结果为:30
A - B 结果为:-10
A * B 结果为:200
B / A 结果为:2
A += 1 后 A 的值为 11
B -= 1 后 B 的值为 19

比较运算符

以下表格列出了 Swift 语言支持的比较运算符,其中变量 A 为 10,变量 B 为 20:

运算符 描述 实例
== 等于 (A == B) 为 false
!= 不等于 (A != B) 为 true
> 大于 (A > B) 为 false
< 小于 (A < B) 为 true
>= 大于等于 (A >= B) 为 false
<= 小于等于 (A <= B) 为 true
实例

以下为比较运算的简单实例:

import Cocoa

var A = 10
var B = 20

print("A == B 结果为:\(A == B)")
print("A != B 结果为:\(A != B)")
print("A > B 结果为:\(A > B)")
print("A < B 结果为:\(A < B)")
print("A >= B 结果为:\(A >= B)")
print("A <= B 结果为:\(A <= B)")

以上程序执行结果为:

A == B 结果为:false
A != B 结果为:true
A > B 结果为:false
A < B 结果为:true
A >= B 结果为:false
A <= B 结果为:true

逻辑运算符

以下表格列出了 Swift 语言支持的逻辑运算符,其中变量 A 为 true,变量 B 为 false

运算符 描述 实例
&& 逻辑与;如果运算符两侧都为 true 则为 true (A && B) 为 false
|| 逻辑或;如果运算符两侧至少有一个为 true 则为 true (A || B) 为 true
! 逻辑非;布尔值取反,使得truefalsefalsetrue !(A && B) 为 true

以下为逻辑运算的简单实例:

import Cocoa

var A = true
var B = false

print("A && B 结果为:\(A && B)")
print("A || B 结果为:\(A || B)")
print("!A 结果为:\(!A)")
print("!B 结果为:\(!B)")

以上程序执行结果为:

A && B 结果为:false
A || B 结果为:true
!A 结果为:false
!B 结果为:true

位运算符

位运算符用来对二进制位进行操作:

  • ~:取反:单目运算符
    具有右结合性;其功能是对参与运算的数的各二进位按位求反。
    例如:
~(1001)
结果为:0110
  • &:按位与
    是双目运算符;其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
  • |:按位或
    是双目运算符,其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就为1。参与运算的两个数均以补码出现。
  • ^:按位异或
    是双目运算符,其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1;反之为0。参与运算数仍以补码出现。
  • <<:左移运算符:
    是双目运算符。左移n位就是乘以2的n次方。 其功能把<<左边的运算数的各二进位全部左移若干位,由<<右边的数指定移动的位数,高位丢弃,低位补0。
    1. 运算规则:
      按二进制形式把所有的数字向左移动对应的位数,高位移出(舍弃),低位的空位补零。
    2. 语法格式:
      需要移位的数字 << 移位的次数

注意:当最高位溢出包括1时,则不适用规则左移n位就是乘以2的n次方。

  • >>:无符号右移运算符

    1. 运算规则:
      按二进制形式把所有的数字向右移动对应的位数,低位移出(舍弃),高位的空位补符号位,即正数补零,负数补1。
    2. 语法格式:
      需要移位的数字 >> 移位的次数
    3. 示例: 11 >> 2,则是将数字11右移2位
      计算过程:
      11的二进制形式为:0000 1011,然后把低位的最后两个数字移出,因为该数字是正数,所以在高位补零。则得到的最终结果是0000 0010。转换为十进制是2。
    4. 数学意义:
      右移一位相当于除2,右移n位相当于除以2的n次方。这里是取商,不包括余数。
  • >>>:有符号右移运算符

    1. 运算规则:
      二进制形式把所有的数字向右移动对应位数,低位移出(舍弃),高位的空位补零。对于正数来说和带符号右移相同,对于负数来说不同。 其他结构和>>相似。
p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

如果指定 A = 156; 及 B = 63; 两个变量对应的二进制为:
A = 1001 1100
B = 0011 1111

运算符 图解 实例
& https://share.weiyun.com/52ERV3D (A & B) 结果为 28,二进制为 0001 1100
| https://share.weiyun.com/5tKae28 (A | B) 结果为 191,二进制为 1011 1111
^ https://share.weiyun.com/5kp5F0h (A ^ B) 结果为 163,二进制为 1010 0011
~ https://share.weiyun.com/53vcuaN (~A) 结果为 99,二进制为 0110 0011
<< https://share.weiyun.com/5L085l0 (A << 1) 结果为 312,二进制为 0001 0011 1000
>> https://share.weiyun.com/5j3GIeV (A >> 1) 结果为 78,二进制为 0100 1110

以下为位运算的简单实例:

import Cocoa

var A = 60  // 二进制为 0011 1100
var B = 13 // 二进制为 0000 1101

print("A&B 结果为:\(A&B)")
print("A|B 结果为:\(A|B)")
print("A^B 结果为:\(A^B)")
print("~A 结果为:\(~A)")

以上程序执行结果为:

A&B 结果为:12
A|B 结果为:61
A^B 结果为:49
~A 结果为:-61

赋值运算

  • =
    简单的赋值运算,指定右边操作数赋值给左边的操作数
  • +=
    相加后再赋值,将左右两边的操作数相加后再赋值给左边的操作数
  • -=
    相减后再赋值,将左右两边的操作数相减后再赋值给左边的操作数
  • *=
    相乘后再赋值,将左右两边的操作数相乘后再赋值给左边的操作数
  • /=
    相除后再赋值,将左右两边的操作数相除后再赋值给左边的操作数
  • %=
    求余后再赋值,将左右两边的操作数求余后再赋值给左边的操作数
  • <<=
    按位左移后再赋值
  • >>=
    按位右移后再赋值
  • &=
    按位与运算后赋值
  • ^=
    按位异或运算符后再赋值
  • |=
    按位或运算后再赋值
运算符 示例
= C = A + BA + B 的运算结果赋值给 C
+= C += A 相当于 C = C + A
-= C -= A 相当于 C = C - A
*= C *= A 相当于 C = C * A
/= C /= A 相当于 C = C / A
%= C %= A 相当于 C = C % A
<<= C <<= 2 相当于 C = C << 2
>>= C >>= 2 相当于 C = C >> 2
&= C &= 2 相当于 C = C & 2
^= C ^= 2 相当于 C = C ^ 2
|= C |= 2 相当于 C = C | 2

以下为赋值运算的简单实例:

var A = 5; var B = 6; var C = 0
        
printConditionD3(A: A, B: B, C: C)
C = A + B; print("A + B 结果为 \(C)")
        
A = 3; C = 5; printConditionD2(A: A, C: C)
C += A; print("C += A 结果为 \(C)")
        
A = 10; C = 15; printConditionD2(A: A, C: C)
C -= A; print("C -= A 结果为 \(C)")
        
A = 6; C = 7; printConditionD2(A: A, C: C)
C *= A; print("C *= A 结果为 \(C)")
        
A = 4; C = 36; printConditionD2(A: A, C: C)
C /= A; print("C /= A 结果为 \(C)")
        
A = 3; C = 8; printConditionD2(A: A, C: C)
C %= A; print("C %= A 结果为 \(C)")
        
C = 0b0100; A = 0b0001; printConditionB(A: A, C: C)
C <<= A; print("C <<= A 结果为 \(numToStr(num: C))")
        
C = 0b100; A = 1; printConditionB(A: A, C: C)
C >>= A; print("C >>= A 结果为 \(numToStr(num: C))")
        
C = 0b1001; A = 0b1010; printConditionB(A: A, C: C)
C &= A; print("C &= A 结果为 \(numToStr(num: C))")
        
C = 0b1001; A = 0b1010; printConditionB(A: A, C: C)
C ^= A; print("C ^= A 结果为 \(numToStr(num: C))")
        
C = 0b1001; A = 0b1010; printConditionB(A: A, C: C)
C |= A; print("C |= A 结果为 \(numToStr(num: C))")
func numToStr(num: Int) -> String
{
    return "0b\(String(format: "%04d", Int(String(num, radix: 2, uppercase: false))!))"
}
    
func printConditionD3(A: Int, B: Int, C: Int)
{
    print("当 A = \(A)、B = \(B)、C = \(C) 时,", separator: ",", terminator: " ")
}
    
func printConditionD2(A: Int, C: Int)
{
    print("当 A = \(A)、C = \(C) 时,", separator: ",", terminator: " ")
}
    
func printConditionB(A: Int, C: Int)
{
    print("当 A = \(numToStr(num: A))、C = \(numToStr(num: C)) 时,", separator: ",", terminator: " ")
}

执行结果为:

当 A = 5、B = 6、C = 0 时, A + B 结果为 11
当 A = 3、C = 5 时, C += A 结果为 8
当 A = 10、C = 15 时, C -= A 结果为 5
当 A = 6、C = 7 时, C *= A 结果为 42
当 A = 4、C = 36 时, C /= A 结果为 9
当 A = 3、C = 8 时, C %= A 结果为 2
当 A = 0b0001、C = 0b0100 时, C <<= A 结果为 0b1000
当 A = 0b0001、C = 0b0100 时, C >>= A 结果为 0b0010
当 A = 0b1010、C = 0b1001 时, C &= A 结果为 0b1000
当 A = 0b1010、C = 0b1001 时, C ^= A 结果为 0b0011
当 A = 0b1010、C = 0b1001 时, C |= A 结果为 0b1011

区间运算符

Swift 提供了两个区间的运算符:闭区间运算符(...)和半开区间运算符(..<

  • 闭区间运算符(...
    闭区间运算符(a...b)定义一个包含从a到b(包括a和b)的所有值的区间,b必须大于等于a。 ‌ 闭区间运算符在迭代一个区间的所有值时是非常有用的,如在for-in循环中。
  • 半开区间运算符(..<
    半开区间(a..<b)定义一个包含从 a 到 b(包括a,不包括 b)的所有值的区间,b 必须大于a。
运算符 实例
闭区间运算符(... 1...5 区间值为 1, 2, 3, 4 和 5
半开区间运算符(..< 1..<5 区间值为 1, 2, 3, 和 4

以下为区间运算的简单实例:

import Cocoa

print("闭区间运算符:")
for index in 1...5 {
    print("\(index) * 5 = \(index * 5)")
}

print("半开区间运算符:")
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
半开区间运算符:
1 * 5 = 5
2 * 5 = 10
3 * 5 = 15
4 * 5 = 20

空合运算符

这个操作符可以用来快速的对 nil 进行判断,当左侧的值是 非 nil时返回其value左侧的值,为nil时返回其右侧的值。
两个条件:表达式a必须是可选类型,默认值b的类型必须要和a存储值的类型一致。空合并运算符 (a ?? b) 将对可选类型a进行空判断,如果a包含一个值就进行解封,否则就返回一个默认值b。

//空合运算符
var strResult : String?
let strDefault = "default string"
var strNew = strResult ?? strDefault
print("strNew:\(strNew)")
        
strResult = "result string"
strNew = strResult ?? strDefault
print("strNew:\(strNew)")

以上程序的执行结果为:

strNew:default string
strNew:result string

其他运算符

Swift 提供了其他类型的的运算符,如一元、二元和三元运算符。

  • 一元运算符对单一操作对象操作(如-a)。一元运算符分前置运算符和后置运算符,前置运算符需紧跟在操作对象之前(如!b),后置运算符需紧跟在操作对象之后(例如c!)。

备注:在Java/C没有类似c!的语法, 在Swift中用在Optional类型取值。

  • 二元运算符操作两个操作对象(如2 + 3),是中置的,因为它们出现在两个操作对象之间。
  • 三元运算符操作三个操作对象,和 C 语言一样,Swift 只有一个三元运算符,就是三目运算符(a ? b : c)。

运算符重载

现有一个向量,我们重载它的+-*+=运算符。

注意: =是不可以进行重载的。

struct Vector3
{
    var x: Double = 0.0
    var y: Double = 0.0
    var z: Double = 0.0
}

注意:以下重载函数要写在class外部,且只能是1个或2个参数

  • 重载 +
// 重载加号(+)
func + (left: Vector3, right: Vector3) -> Vector3 {
    return Vector3(x: left.x + right.x, y: left.y + right.y, z: left.z + right.z)
}
  • 重载减号-
func - (left: Vector3, right: Vector3) -> Vector3 {
    return Vector3(x: left.x - right.x, y: left.y - right.y, z: left.z - right.z)
}
  • 重载乘号*
func * (left: Vector3, right: Vector3) -> Double {
    return left.x * right.x + left.y * right.y + left.z * right.z
}
  • 重载负号-
/*
 重载负号(-),只有一个参数
 由于不知道“-”是放在参数的左侧还是右侧,
 故需要添加关键字prefix,代表“-”是在参数的左侧
 */
prefix func - (value: Vector3) -> Vector3 {
    return Vector3(x: -value.x, y: -value.y, z: -value.z)
}
  • 重载+=
/*
 重载 +=  ,
 由于是把该操作会使left值发生改变,故left需要用到关键字 inout;
 由于“+”方法在之前定义过,故在这个方法中可以直接使用“+”方法
 */
func += (left: inout Vector3, right: Vector3) -> Vector3 {
    left = left + right
    return left
}

实例

var v1 = Vector3(x: 3.0, y: 4.0, z: 5.0)
var v2 = Vector3(x: 7.0, y: 9.0, z: 6.0)
        
print("v1 + v2 结果为:\(v1 + v2)")
print("v1 - v2 结果为:\(v1 - v2)")
print("v1 * v2 结果为:\(v1 * v2)")
print("-v1 结果为:\(-v1)")
print("v1 += v2 结果为:\(v1 += v2)")

以上程序的执行结果为:

v1 + v2 结果为:Vector3(x: 10.0, y: 13.0, z: 11.0)
v1 - v2 结果为:Vector3(x: -4.0, y: -5.0, z: -1.0)
v1 * v2 结果为:87.0
-v1 结果为:Vector3(x: -3.0, y: -4.0, z: -5.0)
v1 += v2 结果为:Vector3(x: 10.0, y: 13.0, z: 11.0)

自定义运算符

对于系统中没有的运算符,需要通过 operator 关键字来定义操作符。

注意:这些函数仍要写在 class 外面。

  • 操作符在参数后面,使用关键字 postfix
// 对于系统中没有的运算符,需要通过 operator 来定义操作符
// postfix 表示操作符应在参数的后面
postfix operator +++
postfix func +++ (vector: inout Vector3) -> Vector3 {
    vector = vector + Vector3(x: 1.0, y: 1.0, z: 1.0)
    return vector
}
  • 操作符应在参数的前面,使用关键字 prefix
// prefix 表示操作符应在参数的前面
prefix operator ---
prefix func --- (vector: inout Vector3) -> Vector3
{
    vector = vector - Vector3(x: 1.0, y: 1.0, z: 1.0)
    return vector
}
  • 中间运算符 infix
infix operator **<: BTPrecedenceL
precedencegroup BTPrecedenceL {
    associativity: left             // 左结合
    higherThan: AdditionPrecedence  // 优先级高于加法运算符
}

func **< (x: Double, y: Double) -> Double {
    return x * y
}
infix operator **>: BTPrecedenceR
precedencegroup BTPrecedenceR {
    associativity: right            //右结合
    lowerThan: AdditionPrecedence   // 优先级低于加法运算符
}

func **> (x: Double, y: Double) -> Double {
    return x * y
}

实例

var v2 = Vector3(x: 7.0, y: 9.0, z: 6.0)

print("v2+++ 结果为:\(v2+++)")
print("---v2 结果为:\(---v2)")

let a = 3.0
let b = 2.0
let c = 4.0
        
print("a **< b **< c = \(a **< b **< c)")
print("1.0 + a **< b **< c = \(1.0 + a **< b **< c)")
print("a **> b **> c = \(a **> b **> c)")
print("1.0 + a **> b **> c = \(1.0 + a **> b **> c)")

以上程序的执行结果为:

v2+++ 结果为:Vector3(x: 8.0, y: 10.0, z: 7.0)
---v2 结果为:Vector3(x: 7.0, y: 9.0, z: 6.0)

a **< b **< c = 24.0
// 此处先计算  a **< b **< c,再加1.0 
1.0 + a **< b **< c = 25.0
a **> b **> c = 24.0
// 此处先计算 1.0 + a
1.0 + a **> b **> c = 32.0

运算符优先级

在一个表达式中可能包含多个有不同运算符连接起来的、具有不同数据类型的数据对象;由于表达式有多种运算,不同的运算顺序可能得出不同结果甚至出现错误运算错误,因为当表达式中含多种运算时,必须按一定顺序进行结合,才能保证运算的合理性和结果的正确性、唯一性。

优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有最低的优先级。

相同优先级中,按结合顺序计算。大多数运算是从左至右计算,只有三个优先级是从右至左结合的,它们是单目运算符、条件运算符、赋值运算符。

基本的优先级需要记住:

  • 指针最优,单目运算优于双目运算,如正负号
  • 先乘除(模),后加减
  • 先算术运算,后移位运算,最后位运算。请特别注意:1 << 3 + 2 & 7 等价于 (1 << (3 + 2))&7
  • 逻辑运算最后计算

详细的优先级参见下表:https://share.weiyun.com/5AuIR4J

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 运算符是一个符号,用于告诉编译器执行一个数学或逻辑运算。 Swift 提供了以下几种运算符: 算术运算符 比较运算...
    零度_不结冰阅读 296评论 0 0
  • 运算符是一中算数逻辑运算符号,用于告诉编译器执行一个数学或逻辑运算。 Swift 提供了以下几种运算符: 算术运算...
    Albert_Li99阅读 2,071评论 0 1
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,118评论 0 13
  • 姓名:李雪 426期努力一组学员 438期反省二组志工 【日精进打卡第56天】 【知~学习】 六项精进大纲 1遍 ...
    乖乖有错阅读 165评论 0 0
  • 最近看百家讲坛,当看到复旦大学韩昇教授讲的《盛唐的背影之张巡守孤城》这一集时,感触颇深。张巡,邓州南阳人,唐玄宗开...
    心灵绿洲阅读 227评论 1 3