Swift 高级运算符

121 阅读3分钟

运算符重载(Operator Overload)

  • 类、结构体、枚举可以为现有的运算符提供自定义的实现,这个操作:运算符重载
struct Point{
    var x = 0,y = 0
    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)
    }
}


var p1 = Point(x:10,y:20)
var p2 = Point(x:10,y:22)
let p3 = p1 + p2
print(p3)

Equatable

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

class Person : Equatable {
    var age:Int
    init(age:Int){
        self.age = age
    }
    // 实现了 == ,就相当于 实现了 !=
    static func == (lhs:Person,rhs:Person) -> Bool {
        lhs.age == rhs.age
    }
}
var p1 = Person(age:10)
var p2 = Person(age:10)
print(p1 == p2)
print(p1 != p2)

func eqauls<T:Equatable>(_ t1:T,_t2:T) -> Bool {
    t1 == t2
}
  • Swift为以下类型提供默认的Equatable实现
  1. 没有关联类型的枚举
enum Answer {
    case wrong
    case right
}
var s1 = Answer.wrong
var s2 = Answer.right
print(s1 == s2)
  1. 只拥有遵守Equatable协议关联类型的枚举
enum Answer: Equatable{
    case wrong(Int) // Int 遵守Equatable协议
    case right
}
var s1 = Answer.wrong(10)
var s2 = Answer.right(10)
print(s1 == s2) // true

enum Answer: Equatable{
    case wrong(Int,String) // Int,String 遵守Equatable协议
    case right
}
var s1 = Answer.wrong(10,"Jack")
var s2 = Answer.right(10,"Rose")
print(s1 == s2) // false 10 == 10,"Jack" != "Rose" 

class Cat {}

enum Answer: Equatable{
    case wrong(Int,String,Cat) // Int,String 遵守Equatable协议,Cat 不是遵守Equatable协议
    case right
}
var s1 = Answer.wrong(10,"Jack")
var s2 = Answer.right(10,"Rose")
print(s1 == s2) // false 10 == 10,"Jack" != "Rose" 

  1. 只拥有遵守Equatable协议存储属性的结构体
struct Point:Equatable{
    var x = 0,y = 0
}
var p1 = Point(x:10,y:20)
var p2 = Point(x:10,y:20)
print(p1 == p2)
  • 引用类型比较存储的地址值是否相等(是否引用着同一个对象),使用恒等运算符 ===、!==
class Person : Equatable {
    var age:Int
    init(age:Int){
        self.age = age
    }
    // 实现了 == ,就相当于 实现了 !=
    static func == (lhs:Person,rhs:Person) -> Bool {
        lhs.age == rhs.age
    }
}
var p1 = Person(age:10)
var p2 = Person(age:10)
var p3 = p1
print(p1 === p3) // true
print(p1 === p2) // false 

Comparable

要想比较2个实例的大小,一般做法是:

  1. 遵守Comparable协议
  2. 重载相应的运算符
// score大的比较大,若score相等,age小的比较大
struct Student:Comparable{
    var age:Int
    var score: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进行声明

  • prifix operator 前缀运算符
  • postfix operator 后缀运算符
  • infix operator 中缀运算符:优先级组