美文网首页
iOS-Swift-高级运算符

iOS-Swift-高级运算符

作者: Imkata | 来源:发表于2020-01-16 15:26 被阅读0次

    一. 溢出运算符(Overflow Operator)

    Swift的算数运算符出现溢出时会抛出运行时错误

    print(Int8.min) // -128
    print(Int8.max) // 127
    print(UInt8.min) // 0
    print(UInt8.max) // 255
    
    var v = UInt8.max
    v += 1 //溢出,抛出如下运行时错误
    //Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    

    Swift有溢出运算符(&+、&-、&*),用来支持溢出运算

    &+

    var v1 = UInt8.max
    var v2 = v1 &+ 1
    print(v1,v2)
    //打印:255 0
    

    可以发现,使用溢出运算符&+之后,v2由255变成0,是循环了一次

    &-

    var v1 = UInt8.min
    var v2 = v1 &- 1
    print(v1,v2) //0 255
    

    也是循环一次,从0变成255了

    &*

    var v1 = UInt8.max
    var v2 = v1 &* 2 //相当于:v1 &+ v1
    print(v1,v2) //255 254
    

    溢出乘其实就是溢出加,就不解释了

    如下图:

    溢出.png

    在Swift官网,找到如下解释图:

    &+本质.png

    上图,8个1就是255,255+1之后都要进1位,所以第1位是1,后8位是0,由于是无符号的计算的时候只看后8位,所以最后结果是0

    同理,如下图:

    &-本质.png

    上图,1代表负数,由于是Int8,所以最小值是-128,减1之后,后7位变成1,第1位变成0,所以最后结果是127

    二. 运算符重载(Operator Overload)

    枚举、结构体、类可以为现有的运算符提供自定义的实现,这个操作叫做:运算符重载

    以前+都是将两个Int、Double类型相加,如何将两个结构体相加?
    使用运算符重载(其实就是将+当做函数名)

    struct Point {
        var x: Int, y: Int
        static func + (p1: Point, p2: Point) -> Point {
            Point(x: p1.x + p2.x, y: p1.y + p2.y)
        }
    }
    
    let p = Point(x: 10, y: 20) + Point(x: 11, y: 22)
    print(p) // Point(x: 21, y: 42)
    

    常用运算符重载:

    默认是中缀运算符
    static func + (p1: Point, p2: Point) -> Point {
        Point(x: p1.x + p2.x, y: p1.y + p2.y)
    } //两个点相加
    
    static func - (p1: Point, p2: Point) -> Point {
        Point(x: p1.x - p2.x, y: p1.y - p2.y)
    }  //两个点相减
    
    static prefix func - (p: Point) -> Point {
        Point(x: -p.x, y: -p.y)
    } //取负 (前缀)
    
    static func += (p1: inout Point, p2: Point) {
        p1 = p1 + p2
    } //+=
    
    static prefix func ++ (p: inout Point) -> Point {
        p += Point(x: 1, y: 1)
        return p
    } //++ (前缀)
    
    static postfix func ++ (p: inout Point) -> Point {
        let tmp = p
        p += Point(x: 1, y: 1)
        return tmp
    } //++ (后缀)
    
    static func == (p1: Point, p2: Point) -> Bool {
        (p1.x == p2.x) && (p1.y == p2.y)
    } //==
    

    三. Equatable

    要想得知2个实例是否等价,一般做法是遵守 Equatable 协议,重载 == 运算符,与此同时,等价于重载了 != 运算符

    class Person : Equatable {
        var age: Int
        init(age: Int) {
            self.age = age
        }
        static func == (lhs: Person, rhs: Person) -> Bool {
            return lhs.age == rhs.age
        }
    }
    var p1 = Person(age: 10)
    var p2 = p1
    print(p1 == p2) //true
    print(p1 != p2) //false
    print(p1 === p2) //true 比较存储的地址值是否相等
    

    其实,不遵守Equatable协议,通过重载也是可以实现比较是否相等的,但是建议遵守Equatable协议,原因有两个:1.遵守这个协议代表明摆着告诉别人我可以做比较 2.有些地方传入的参数要求是遵守这个协议的东西,你遵守这个协议就可以传进去

    上面代码最后一行:引用类型比较存储的地址值是否相等(是否引用着同一个对象),使用恒等运算符 === 、!==

    四. 编译器自动实现==

    Swift为以下类型提供默认的Equatable实现:

    1. 没有关联类型的枚举
    2. 只拥有遵守Equatable协议关联类型的枚举
    3. 只拥有遵守Equatable协议存储属性的结构体
    //1.没有关联类型的枚举
    //编译器直接拿到枚举存储在内存中的值来比较
    enum Answer {
        case wrong
        case right
    }
    var s1 = Answer.wrong
    var s2 = Answer.wrong
    print(s1 == s2) //true
    
    //2.只拥有遵守Equatable协议关联类型的枚举
    //Int、String都遵守Equatable协议,就算Answer遵守Equatable协议后不实现==,编译器也会帮你实现,因为编译器已经知道应该怎么去实现了
    enum Answer : Equatable {
        case wrong(Int, String)
        case right
    }
    var s1 = Answer.wrong(10, "Jack")
    var s2 = Answer.wrong(10, "Jack")
    print(s1 == s2) //true
    
    //3.只拥有遵守Equatable协议存储属性的结构体
    //Int遵守Equatable协议,就算Point遵守Equatable协议后不实现==,编译器也会帮你实现,因为编译器已经知道应该怎么去实现了
    struct Point : Equatable {
        var x: Int, y: Int
    }
    var p1 = Point(x: 10, y: 20)
    var p2 = Point(x: 11, y: 22)
    print(p1 == p2) // false
    print(p1 != p2) // true
    

    五. Comparable

    要想比较两个实例的大小,一般做法是:遵守Comparable协议,重载相应的运算符

    //规则:score大的比较大,若score相等,age小的比较大
    struct Student : Comparable {
        var score: Int
        var age: Int
        init(score: Int, age: Int) {
            self.score = score
            self.age = age
        }
        static func < (lhs: Student, rhs: Student) -> Bool {
            (lhs.score < rhs.score) || (lhs.score == rhs.score && lhs.age > rhs.age)
        }
        static func > (lhs: Student, rhs: Student) -> Bool {
            (lhs.score > rhs.score) || (lhs.score == rhs.score && lhs.age < rhs.age)
        }
        static func <= (lhs: Student, rhs: Student) -> Bool {
            !(lhs > rhs)
        }
        static func >= (lhs: Student, rhs: Student) -> Bool {
            !(lhs < rhs)
        }
    }
    
    var stu1 = Student(score: 100, age: 20)
    var stu2 = Student(score: 98, age: 18)
    var stu3 = Student(score: 100, age: 20)
    print(stu1 > stu2) // true
    print(stu1 >= stu2) // true
    print(stu1 >= stu3) // true
    print(stu1 <= stu3) // true
    print(stu2 < stu1) // true
    print(stu2 <= stu1) // true
    

    六. 自定义运算符(Custom Operator)

    可以自定义新的运算符,在全局作用域使用operator进行声明

    自定义运算符规则:

    prefix operator 前缀运算符
    postfix operator 后缀运算符
    infix operator 中缀运算符 : 优先级组
    
    precedencegroup 优先级组 {
        associativity: 结合性(left\right\none)
        higherThan: 比谁的优先级高
        lowerThan: 比谁的优先级低
        assignment: true代表在可选链操作中拥有跟赋值运算符一样的优先级
    }
    

    举例:自定义前缀运算符

    prefix operator +++
    prefix func +++ (_ i: inout Int) {
        i += 2
    }
    
    var age = 10
    +++age
    print(age) //12
    

    举例:自定义中缀运算符

    infix operator +- : PlusMinusPrecedence
    precedencegroup PlusMinusPrecedence {
        associativity: none //结合性为none,不允许有结合性,就是不允许例如:a+b+c这样的操作
        higherThan: AdditionPrecedence //高于加号的优先级
        lowerThan: MultiplicationPrecedence //低于乘号的优先级
        assignment: true //true代表在可选链操作中拥有跟赋值运算符(=)一样的优先级
    }
    
    struct Point {
        var x = 0, y = 0
        static func +- (p1: Point, p2: Point) -> Point {
            return Point(x: p1.x + p2.x, y: p1.y - p2.y)
        }
    }
    
    var p1 = Point(x: 10, y: 20)
    var p2 = Point(x: 5, y: 15)
    var p3 = p1 +- p2
    print(p3)  //Point(x: 15, y: 5)
    
    class Person {
        var age = 10
        var point:Point = Point()
    }
    var p:Person? = Person()
    p?.point +- Point(x: 10, y: 20) //如果+-左边的p为nil,那么+-右边的代码就不会执行 (你就理解为在可选链中+-就相当于=)
    

    Apple参考文档1:https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations
    Apple参考文档2:
    https://docs.swift.org/swift-book/ReferenceManual/Declarations.html

    相关文章

      网友评论

          本文标题:iOS-Swift-高级运算符

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