swift 之运算符

基本概念

  • 一元运算符:对一个目标进行操作,如一元前缀运算符(!flag)和用于解包的一元后缀运算符(b!)。
  • 二元运算符(中缀)。
  • 三元运算符: flag ? a : b

赋值和算术运算符

swift支持c中大多数标准运算符,并且:

  • 赋值运算符(=)不会返回值,防止误用为等于(==)。
  • 算术运算符(+、-、*、/、 %)可以检测并阻止值溢出,甚至提供了可以允许值溢出的算术运算符。
  • 加法运算符可以用于字符串拼接。
  • 一元算术运算符:切换正负值,比如(+5,-5)。
  • 取余运算符需要注意:被除数正负号不会被忽略,除数正负号会被忽略。

print(3 % 2) // 1
print(-3 % 2) // -1
print(3 % -2) // 1

溢出运算符

  • 默认情况下,当给一个整数赋超过他容量的值时,swift会报错而不是生成一个无效的数,这给我们操作过大过小的数提供了额外的安全性。
  • 提供三个溢出运算符让系统支持整数溢出运算:
    • 溢出加法:&+
    • 溢出减法:&-
    • 溢出乘法:&*
 var a: UInt8 = 0xff
 a &+= 1
 print(a) // 0
 a = 0
// a -= 1  error
 a &-= 1
 print(a) // 255

合并空值运算符

  • a ?? b: a有值则解包,如果是nil,则返回默认值b。
  • 文档要求: 表达式a为可选类型,表达式b必须与a的存储类型相同。(实际操作则不然)
  • a ?? b 等价于 a != nil ? a! : b
  • 如果a的值不是nil,那么b的值不会被考虑。
 //正常用法
 var a : Int? = nil
 var b: Int = 255

 print(a ?? b ) // 255
 a = 20
 print(a ?? b ) // 20
 print(type(of: a ?? b)) // Int

 //这样不会报错,但是明显c和d类型不同
 var c: Int? = nil
 let d: String = "abc"
 print(c ?? d) // abc

 //Expression type '(_) -> _' is ambiguous without more context
// print(type(of: c ?? d))

区间运算符

  • 闭区间: (a...b)
  • 半开区间: (a..
  • 单侧区间: (a...) 或者 (...b)
  • 倒叙区间: (a...b).reversed()

位运算

  • 按位取反:~
  • 与: &
  • 或:|
  • 异或:^
  • 移位: >> 和 <<

常见应用:

  • 交换两个变量的值
func swap(_ a: inout Int,_ b: inout Int) {
    a = a ^ b
    b = a ^ b
    a = a ^ b
 }
 var a = 10
 var b = 8
 print("a = \(a) b = \(b)")
 swap(&a, &b)
 print("a = \(a) b = \(b)")
  • 无符号二进制中1的个数
 func countOfOnes(_ num: UInt) -> UInt {
    var count: UInt = 0
    var temp = num
    while temp != 0 {
        count += 1
        temp = temp & (temp - 1)
    }
    return count
 }
  • 判断无符号整型是否是2的整数次幂
 func isPowerOfTwo(_ num: UInt) -> Bool {
    return num & (num - 1) == 0
 }
  • 缺失的数字
 func findLostNum(_ nums: [UInt]) -> UInt {
    return nums.reduce(0) { $0 ^ $1}
 }
  • 缺失的两个数字: 分组异或
func findTwoLostNumbers(_ nums: [UInt]) -> (UInt,UInt) {
    let temp = nums.reduce(0) { $0 ^ $1}
    var flag: UInt = 1
    while temp & flag == 0 {
        flag <<= 1
    }
    var ans: (UInt,UInt) = (0,0)
    for num in nums {
        if num & flag == 0 {
            ans.0 ^= num
        } else {
            ans.1 ^= num
        }
    }
    return ans
 }

运算符重载

  • 类和结构体可以为现有运算符提供自定义实现,叫做运算符重载。
 struct Vector2D {
    var x: Int
    var y: Int
    var description: String {
        return "(x: \(x), y: \(y))"
    }
 }

 extension Vector2D {
    static func + (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y + right.y)
    }
 }

 let vector = Vector2D(x: 1, y: 2)
 let another = Vector2D(x: 2, y: 5)
 let combineVector = vector + another
 print("vector1: \(vector.description) another: \(another.description) combineVector: \(combineVector.description)")
 //vector1: (x: 1, y: 2) another: (x: 2, y: 5) combineVector: (x: 3, y: 7)
  • 一元运算符重载: 需要声明是前缀还是后缀(prefix or postfix)
 extension Vector2D {
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
 }

 let positive = Vector2D(x: 3, y: 5)
 let negative = -positive
 print("positive: \(positive.description) negative: \(negative.description)") //positive: (x: 3, y: 5) negative: (x: -3, y: -5)
  • 组合赋值运算符重载:左参数需要为 inout类型
 extension Vector2D {
    static func += (left: inout Vector2D, right: Vector2D) {
        left.x += right.x
        left.y += right.y
    }
 }

 var original = Vector2D(x: 2, y: 3)
 let toAdd = Vector2D(x: 4, y: 5)
 original += toAdd
 print(original.description) //(x: 6, y: 8)
  • 等价运算符的重载:需要遵循Equatable协议,swift为以下自定义类型提供等价运算符的合成实现。

    • 只拥有遵循Equatable协议的存储属性的结构体
    • 只拥有遵循Equatable协议的关联类型的枚举
    • 没有关联类型的枚举
 extension Vector2D: Equatable {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return left.x == right.x && left.y == right.y
    }
 }

自定义运算符

  • 用operator声明
  • 用prefix、postfix、infix限定
 prefix operator ++
 extension Vector2D {
    static prefix func ++ (vector: inout Vector2D) {
        vector += vector
    }
 }
var vector = Vector2D(x: 1, y: 2)
 ++vector
 print("vector: \(vector.description)") //vector: (x: 2, y: 4)
  • 自定义中缀运算符需要制定优先级和结合性: 优先级组
    • 使用系统优先级组
 infix operator +- : AdditionPrecedence
 extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
 }

 infix operator *^: MultiplicationPrecedence
 extension Vector2D {
    static func *^ (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x * right.x, y: left.y * left.y + right.y * right.y)
    }
 }

 let first = Vector2D(x: 1, y: 2)
 let second = Vector2D(x: 3, y: 7)
 let third = Vector2D(x: 2, y: 2)
 //根据优先级组:先算 *^ 再算 +-
 print("vector: \((first +- second *^ third).description)") //vector: (x: 7, y: -51)
* 使用自定义优先级组
infix operator +- : AdditionPrecedence
 extension Vector2D {
    static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x + right.x, y: left.y - right.y)
    }
 }
  precedencegroup UserDefinePrecedence {
     associativity: left
     lowerThan: AdditionPrecedence
  }
 infix operator *^: UserDefinePrecedence
 extension Vector2D {
    static func *^ (left: Vector2D, right: Vector2D) -> Vector2D {
        return Vector2D(x: left.x * right.x, y: left.y * left.y + right.y * right.y)
    }
 }
 
 let first = Vector2D(x: 1, y: 2)
 let second = Vector2D(x: 3, y: 7)
 let third = Vector2D(x: 2, y: 2)
 //根据优先级组:先算 +- 再算 *^
 print("vector: \((first +- second *^ third).description)") //vector: (x: 8, y: 29)

你可能感兴趣的:(swift 之运算符)