美文网首页
swift 之运算符

swift 之运算符

作者: 枯树恋 | 来源:发表于2020-01-15 16:06 被阅读0次

    基本概念

    • 一元运算符:对一个目标进行操作,如一元前缀运算符(!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..<b)
    • 单侧区间: (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 之运算符

          本文链接:https://www.haomeiwen.com/subject/fqbtzctx.html