高级运算符
溢出运算符 (Overflow Operator)
- Swift的算术运算符出现溢出时会抛出运行时错误
- Swift有溢出运算符
&+、&-、&*
, 用来支持溢出运算
print(UInt8.min) //0
print(UInt8.max) //255
var v1 = UInt8.max // 255
//v1 += 1 超出了范围 直接报错
var v2 = v1 &+ 1
print("v2",v2)// 0
// 使用溢出运算符可以避免报错,但+是在范围内循环的
v2 = v1 &* 2
print("v2",v2)// 254 即为 v2 = v1 &+ v1
运算符重载 (Operator reload)
// 运算符重载
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 prefix func - (p1: Point) -> Point {
Point(x: -p1.x, y: -p1.y )
}
static func += (p1: inout Point, p2: Point) {
开 p1 = p1 + p2
}
}
//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: 11, y: 22)
var p3 = Point(x: 12, y: 33)
let p4 = p1 + p2 + p3
print(p4)
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: 11)
print(p1 == p2) // false
print(p1 != p2) // true
-
Swift为以下类型提供默认的Equatable实现
- 没有关联类型的枚举
- 只拥有遵守Equatable协议关联类型的枚举
- 只拥有遵守Equatable协议存储属性的结构体
-
引用类型比较存储的地址值是否相等(是否引用着同一个对象), 使用恒等运算符=== 、!===
Comparable
- 要比较2个实例的大小, 一般的做法是:
- 遵守Comparable 协议
- 重载相应的运算符
自定义运算符 (Custom Operator)
- 可以自定义新的运算符: 在全局作用域使用operator进行声明
prefix operator 前缀运算符
postfix operator 后缀运算符
infix operator 中缀运算符: 优先级组
precedencegroup 优先级组 {
associativity: 结合性(left/right/none)
higherThan: 比谁的优先级高
lowerThan: 比谁的优先级低
assignment: true代表在可选链操作中拥有跟赋值运算符一样的优先级
}
扩展 (Extension)
- Swift 中的扩展,有点类似OC中的Category
- 扩展可以为枚举、结构体、类、协议添加新功能
- 可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等
- 扩展不能办到的事情
- 不能覆盖原有的功能
- 不能添加存储属性,不能像已有的属性添加属性观察器
- 不能添加父类
- 不能添加指定初始化器,不能添加反初始化器
- 。。。
extension Double {
var km: Double { self / 1000.0}
var m: Double { self }
var dm: Double { self * 10.0}
var cm: Double { self * 100.0}
var mm: Double { self * 1000.0}
}
var d = 100.0
print(d.km) // 0.1
print(d.m) // 100.0
print(d.dm) // 1000.0
print(d.cm) // 10000.0
// 添加下标给Array
extension Array {
subscript(nullable idex: Int) -> Element? {
if (startIndex..<endIndex).contains(idex) {
return self[idex]
}
return nil
}
}
var arr: Array<Int> = [10, 20, 30]
print(arr[nullable: 2] as Any)
print(arr[nullable:4] as Any)
// 给Int类型添加功能
extension Int {
func repeats(task: () -> Void) {
for _ in 0..<self { task() }
}
mutating func square() -> Int {
self = self * self
return self
}
// 嵌套类型
enum Kind { case negative, zero, positive}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0 : return .positive
default:
return .negative
}
}
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex { decimalBase *= 10}
return (self / decimalBase) % 10
}
}
3.repeats {
print(1)
}
// 1 1 1 打印3次1
var age = 123
print(age.square())
// 15129 就是123的平方
print(10.kind)
// positive 10的类型是 positive
print(age[1])
// 2 打印十位上的数字
协议 初始化器
- 如果希望自定义初始化器的同时,编译器也能够生成默认初始化器
- 可以在扩展中编写自定义初始化器
- required初始化器,不能写在扩展中
class Person {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
extension Person : Equatable {
static func == (left: Person, rigtht: Person) -> Bool {
left.age == rigtht.age && left.name == rigtht.name
}
convenience init() {
self.init(age: 0, name: "")
}
}
struct Point {
var x: Int = 0
var y: Int = 0
}
extension Point {
init(_ point: Point) {
self.init(x: point.x, y: point.y)
}
}
var p1 = Point(x: 10)
var p2 = Point(p1)
- 如果一个类型已经实现了协议的所有要求,但是还没有声明它遵守了这个协议,可以通过扩展来让它遵守这个协议
protocol TestProtocol {
func test()
}
class TestClass {
func test() {
print("test")
}
}
extension TestClass : TestProtocol { }
// 编写一个函数,判断一个整数是否为奇数
func isOdd <T: BinaryInteger>(_ i: T) -> Bool { i % 2 != 0 }
extension BinaryInteger {
func isOdd() -> Bool { self % 2 != 0 }
}
- 扩展可以给协议提供默认实现,也间接实现 可选协议 的效果
- 扩展可以给协议扩充 协议中从未声明过的方法
protocol TestProtocol {
func test1()
}
extension TestProtocol {
func test1() {
print("Protocol test1")
}
func test2() {
print("Protocol test2")
}
static func test3() {
print("Protocol test3")
}
}
/*
class TestClass : TestProtocol { }
var cls = TestClass()
cls.test1()
cls.test2()
TestClass.test3()
*/
class TestClass : TestProtocol {
func test1() {
print("Class test1")
}
func test2() {
print("Class test2")
}}
var cls = TestClass()
cls.test1() // Class test1
cls.test2() // Class test2
TestClass.test3() // Protocol test3
var cls2: TestProtocol = TestClass()
cls2.test1() // Class test1
/// 由于协议里面没有声明test2,所以不确定指向的类有没有实现test2,
/// 所以优先去协议里找,所以调用的是协议里的Protocol test2
cls2.test2() // Protocol test2
TestClass.test3() // Protocol test3
扩展泛型
class Stack<E> {
var elements = [E]()
func push(_ element: E) { elements.append(element) }
func pop() -> E { elements.removeLast() }
func size() -> Int { elements.count }
}
// 扩展中依然可以使用原类型中的泛型类型
extension Stack {
func top() -> E { elements.last! }
}
// 符合条件才扩展
extension Stack : Equatable where E : Equatable {
static func == (left: Stack, right: Stack) -> Bool {
left.elements == right.elements
}
}