Swift 运算符重载

Swift中的运算符重载

一、概念

类和结构体可以为现有的运算符提供自定义的实现,称为运算符重载。

二、种类
  • 一元运算符重载
  • 组合赋值运算符重载
  • 等价运算符重载
  • 自定义运算符重载
the code
struct Vector2D {
    var x = 0.0
    var y = 0.0
}
let vector2D = Vector2D(x: 2.0, y: 3.0)
let anotherVector2D = Vector2D(x: 1.0, y: 4.0)
//正常不使用运算符重载也可以实现,但是这样写不通用也不方便后期修改
let newVector2D = Vector2D(x: vector2D.x + anotherVector2D.x, y: vector2D.y + anotherVector2D.y)
print(newVector2D)

如果使用运算符重载

struct Vector2D {
    var x = 0.0
    var y = 0.0
}

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

let vector2D = Vector2D(x: 2.0, y: 3.0)
let anotherVector2D = Vector2D(x: 1.0, y: 4.0)
//正常不使用运算符重载也可以实现,但是这样写不通用也不方便后期修改
//let newVector2D = Vector2D(x: vector2D.x + anotherVector2D.x, y: vector2D.y + anotherVector2D.y)
//如果使用运算符重载,直接将两个变量进行相加就可以了
let newVector2D = vector2D + anotherVector2D
print(newVector2D)

一元运算符重载:要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 func 关键字之前指定 prefix 或者 postfix 限定符。

struct Vector2D {
    var x = 0.0
    var y = 0.0
}
//一元运算符重载: 要实现前缀或者后缀运算符,需要在声明运算符函数的时候在 func 关键字之前指定 prefix 或者 postfix 限定符
extension Vector2D {
//使用前缀运算符
    static prefix func - (vector: Vector2D) -> Vector2D {
        return Vector2D(x: -vector.x, y: -vector.y)
    }
    //使用后缀运算符
extension Vector2D {
    static postfix func ++ (vector: inout Vector2D) -> Vector2D {
        vector = vector + Vector2D(x: 1, y: 1)
        return vector
    }
}
}
let vector = Vector2D(x: 2.0, y: 2.0)
let newVector = -vector
print(newVector)

组合赋值运算符重载:

  • 组合赋值运算符将赋值运算符( = )与其它运算符进行结合
  • 在实现的时候,需要把运算符的左参数设置成 inout 类型,因为这个参数的值会在运算 符函数内直接被修改
struct Vector2D {
    var x = 0.0
    var y = 0.0
}
extension Vector2D {
    static func += (left: inout Vector2D, right: inout Vector2D) {
        left = left + right
    }
}
var vector1 = Vector2D(x: 5, y: 8)
var vector2 = Vector2D(x: 2, y: 9)
vector1 += vector2
print("vector1 x is \(vector1.x), y is \(vector1.y)")

等价运算符重载

  • 自定义类和结构体不接收等价运算符的默认实现,也就是所谓的“等于”运算符( == ) 和“不等于”运算符( != )
  • 要使用等价运算符来检查你自己类型的等价,需要和其他中缀运算符一样提供一个“等 于”运算符,并且遵循标准库的 Equatable 协议
struct Vector2D {
    var x = 0.0, y = 0.0
}
//要扩展的类遵循了标准库的 Equatable 协议
extension Vector2D: Equatable {
    static func == (left: Vector2D, right: Vector2D) -> Bool {
        return left.x == right.x && left.y == right.y
    }
}
var vector1 = Vector2D(x: 2, y: 4)
var vector2 = Vector2D(x: 1, y: 4)
print(vector1 == vector2)

在Swift中会为以下自定义类型提供默认Equatable协议(等价运算符合成)的实现

  • 没有关联类型的枚举
  • 只拥有遵循 Equatable 协议关联类型的枚举
  • 只拥有遵循 Equatable 协议存储属性的结构体
//在声明结构体的时候声明的是存储型属性,并且遵循 Equatable 协议
struct Vector2D: Equatable {
    var x = 0.0
    var y = 0.0
}
let vector1 = Vector2D(x: 2.0, y: 3.0)
let vector2 = Vector2D(x: 2.0, y: 4.0)
print(vector1 == vector2)

自定义运算符

  • 新的运算符要在全局作用域内,使用 operator 关键字进行声明,同时还要指定 prefix 、infix 或者 postfix 限定符
//自定义运算符   prefix:前缀  infix:中缀    postfix:后缀
struct Vector2D {
    var x = 0.0, y = 0.0
}
// 使用了 operator 关键字进行声明,并且指定了 prefix 前缀限定符
prefix operator +++ 
extension Vector2D {
    static prefix func +++(vector: inout Vector2D) -> Vector2D {
        vector += vector
        return vector
    }
}
var vector1 = Vector2D(x: 2.0, y: 4.0)
let newVector = +++vector1
print("newVector x is \(newVector.x), y is \(newVector.y)")

自定义中缀运算符的优先级和结合性

  • 自定义的中缀( infix )运算符也可以指定优先级和结合性
  • 每一个自定义的中缀运算符都属于一个优先级组
  • 优先级组指定了自定义中缀运算符和其他中缀运算符的关系
/*
 precedencegroup
 定义了一个操作符优先级别。操作符优先级的定义和类型声明有些相似,一个操作符比需 要属于某个特定的优先级。Swift 标准库中已经定义了一些常用的运算优先级组,比如加法 优先级 ( AdditionPrecedence ) 和乘法优先级 ( MultiplicationPrecedence ) 等,你可以在这里找 到完整的列表。如果没有适合你的运算符的优先级组,你就需要像我们在例子中做得这 样,自己指定结合律方式和优先级顺序了。
 associativity
 定义了结合律,即如果多个同类的操作符顺序出现的计算顺序。比如常⻅的加法和减法都 是 left ,就是说多个加法同时出现时按照从左往右的顺序计算 (因为加法满足交换律,所 以这个顺序无所谓,但是减法的话计算顺序就很重要了)。点乘的结果是一个 Double ,不 再会和其他点乘结合使用,所以这里是 none ;
 higherThan
 运算的优先级,点积运算是优先于乘法运算的。除了 higherThan ,也支持使用 lowerThan 来指定优先级低于某个其他组。
 infix
 表示要定义的是一个中位操作符,即前后都是输入;其他的修饰子还包括 prefix 和 postfix ,不再赘述;
 */

struct Vector2D {
    var x = 0.0, y = 0.0
}

//声明自定义运算符: 加减
infix operator +- : PlusMinusPrecedence
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)
    }
}
//自定义中缀运算符的优先级和结合性
precedencegroup PlusMinusPrecedence {
    associativity: none                   // 结合性(left、right、none)
    higherThan: AdditionPrecedence        // 比谁的优先级高
    lowerThan: MultiplicationPrecedence   // 比谁的优先级低
    assignment: true                      // 在可选链操作中拥有跟赋值运算符一样的优先级
}
var vector1 = Vector2D(x: 2.0, y: 6.0)
var vector2 = Vector2D(x: 3.0, y: 4.0)
var vector3 = Vector2D(x: 2.0, y: 4.0)
let newVector = vector1 +- vector2 *^ vector3
print("newVector x is \(newVector.x), y is \(newVector.y)")
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值