当前位置: 首页 > news >正文

swift-14-可选项的本质、运算符重载、扩展( Extension )

一、可选项的本质

1.1 可选项的本质是enum类型

public enum Optional<Wrapped> : ExpressibleByNilLiteral
case none
case some(Wrapped)
public init_ some: Wrapped)
}

1.2 平时写的可选项对应的原始写法

var age: Int? = 10
var age0: Optional<Int> = Optional<Int>.some(10)
var age1: Optional = .some(10)
var age2 = Optional.some(10)
var age3 = Optional(10)
age = nil
age3 = .nonevar age: Int? = nil
var age0 = Optional<Int>.none
var age1: Optional<Int> = .none可以混合写
var age: Int? = .none
age = 10
age = .some(20) age = nil

1.3 平时我们写的非枚举可选(本质就是枚举)和非可选类型支持switch 的写法

var age: int ? = 10
switch age {case let v?:
print("some", v) 
case nil:
print("none")
}
上面的写法等价于 
if let v = age
{
print("1", v)
}
else {
print ("2" )
}
var age: int = 10 switch age {
case let .some(v):
print("some", v)
case .none:
print("none")
}

1.4 多重可选项

var age_: Int? = 10
var age: Int?? = age_
age = nilvar age0 = Optional.some(Optional.some(10)) age0 = .none
var age1: Optional<Optional> = .some(.some(10)) age1 = .nonevar age: Int?? = 10
var age0: Optional<Optional> = 10

二、溢出运算符(Overflow Operator)

2.1 类型范围区间

print(Int8.min) // -128print(Int8.max) // 127print(UInt8.min) // 0
print(UInt8.max) // 255

2.2 那么溢出之后如何处理

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

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

 假如范围是-128到127 之间,只用溢出运算符( &+ &- &*)后,数字依然会在-128到127这间进行变化,例如 当前数是a=127 使用了b=a&+ 1 ,那么b的值是-127,又回到最小的-127了


var min = UInt8.min 
print(min &- 1) // 255, Int8.maxvar max = UInt8.max
print(max &+ 1) // 0, Int8.min
print(max &* 2) // 254, 等价于  max &+ max

三、运算符重载( Operator Overload 

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

注:重载的运算符一般放在对应的类、结构体、枚举内,写成static 的形式

struct Point {
var x: Int, y: Int
}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)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)
}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 协议,重载 == 运算符

1、与此同时,等价于重载了  != 运算符

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

注:有两种方式实现,第一种是遵守Equatable,第二种重载==运算符,但是一般情况下如果要比较2个实例是否等价,都需要遵守Equatable,因为如果我要定义一个比较方法带范型的参数的时候,范型参数需要制定具体的遵守的类型

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


1、没有关联类型的枚举

enum Answer {
case wrong case right
}
var s1 = Ayswer. wrong
var s2 = Answer.right
print (s1 == s2)


2、只拥有遵守 Equatable 协议关联类型的枚举(枚举遵守 Equatable不用实现Equatable定义的方法,但其他的必须实现Equatable定义的方法才行)


3、只拥有遵守 Equatable 协议存储属性的结构体
一下Point : Equatable 提供了默认的实现,Point遵守Equatable也不用再去实现Equatable定义的方法

struct Point : Equatable {
var x = 0, y = 0
}

4、如果是类的话,必须自己实现Equatable定义的额方法

5、引用类型比较存储的地址值是否相等(是否引用着同一个对象),使用恒等运算符 === !== 

 

五、Comparable

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

// 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进行声明

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

 

struct Point {
var x: Int, y: Int
static prefix func +++ (point: inout Point) -> Point {
point = Point(x: point.x + point.x, y: point.y + point.y)
return point
}
static func +- (left: Point, right: Point) -> Point {
return Point(x: left.x + right.x, y: left.y - right.y)
}
static func +- (left: Point?, right: Point) -> Point {
print("+-")
return Point(x: left?.x ?? 0 + right.x, y: left?.y ?? 0 - right.y)
}
}struct Person {
var point: Point
}
var person: Person? = nil
person?.point +- Point(x: 10, y: 20)

七、扩展( Extension 

 Swift中的扩展,有点类似于OC中的分类(Category)
 扩展可以为枚举、结构体、类、协议添加新功能
可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等等


 扩展不能办到的事情
不能覆盖原有的功能
不能添加存储属性,不能向已有的属性添加属性观察器
不能添加父类
不能添加指定初始化器,不能添加反初始化器  ...

7.1 计算属性、下标、方法、嵌套类型

extension Double {
var km: Double { self * 1_000.0 }
var m: Double { self }
var dm: Double { self / 10.0 }
var cm: Double { self / 100.0 }
var mm: Double { self / 1_000.0 }
}var b = 100.0b.km
为数组扩展,防止越界
extension Array {
subscript(nullable idx: Int) -> Element? {
if (startIndex..<endIndex).contains(idx) {
return self [idx]
}
return nil
}
}

为int 进行扩展

extension Int {
func repetitions(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
}
}

7.2 协议、初始化器

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, right: Person) -> Bool {
left.age == right.age && left.name == right.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()
var p2 = Point(x: 10)
var p3 = Point(y: 20)
var p4 = Point(x: 10, y: 20)
var p5 = Point(p4)

required初始化器也不能写在扩展中 

 八、协议

如果一个类型已经实现了协议的所有要求,但是还没有声明它遵守了这个协议
可以通过扩展来让它遵守这个协议

protocol TestProtocol {
func test()
}
class TestClass {
func test() {
print("test")
}
}
extension TestClass : TestProtocol {}

编写一个函数,判断一个整数是否为奇数?

谁都可以调用
func isOdd<T: BinaryInteger>(_ i: T) -> Bool { i % 2 != 0
}只为 BinaryInteger 进行扩展isOdd
extension BinaryInteger {
func isOdd() -> Bool { self % 2 != 0 }
}

扩展可以给协议提供默认实现,也间接实现『可选协议』的效果

扩展可以给协议扩充『协议中从未声明过的方法』

protocol TestProtocol {
func test1()
}
extension TestProtocol {
func test1() {
print("TestProtocol test1")
}
func test2() {
print("TestProtocol test2")
}
}class TestClass : TestProtocol {}
var cls = TestClass()cls.test1() // TestProtocol test1cls.test2() // TestProtocol test2

 

class TestClass : TestProtocol {} var cls = TestClass()
cls.test1() // TestProtocol test1 cls.test2() // TestProtocol test2
var cls2: TestProtocol = TestClass() cls2.test1() // TestProtocol test1   cls2.test2() // TestProtocol test2

var cls2: TestProtocol = TestClass()

TestProtocol 这里面没有声明test2,所以他不能确定将来指向的实列对象有没有有没有test2的实现

var cls2: TestProtocol = TestClass() 

cls2.test2() 这个就当实力里面可能不存在的,就当他不存在,就不从实列里面去找,先从TestProtocol里面去优先找,于是就是下边的这种情况

cls2.test1() test1协议里面定义了test1,他指向的实列对象必须实现test1,因此这个就先从TestClass()里面找

var cls2: TestProtocol = TestClass()
cls2.test1() // TestClass test1
cls2.test2() // TestProtocol test2

class TestClass : TestProtocol {
func test1() { print("TestClass test1") }
func test2() { print("TestClass test2") }
}
var cls = TestClass()
cls.test1() // TestClass test1
cls.test2() // TestClass test2
var cls2: TestProtocol = TestClass()
cls2.test1() // TestClass test1
cls2.test2() // TestProtocol test2

 

 

九、泛型

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
}
}

相关文章:

  • 班车服务系统扩展到多场景(穿梭车、周转车)的升级过程中,遗传算法和蚁群算法的实现示例
  • RAG 知识库核心模块全解(产品视角 + 技术细节)
  • day37
  • 项目开发中途遇到困难的解决方案
  • 详解Redis的热点key问题
  • Python 数据分析与可视化 Day 2 - 数据清洗基础
  • 【云创智城】YunCharge充电桩系统-深度剖析OCPP 1.6协议及Java技术实现:构建高效充电桩通信系统
  • 黑马程序员新版Linux学习笔记——第二部分 基础命令
  • 零基础学前端-传统前端开发(第四期-JS基础)
  • 西门子S7通信协议抓包分析应用
  • Springboot仿抖音app开发之Nacos 分布式服务与配置中心(进阶)
  • moments_object_model_3d这么理解
  • 蓝牙 5.0 新特性全解析:传输距离与速度提升的底层逻辑(面试宝典版)
  • Mac电脑 窗口分屏管理 Magnet Pro
  • 20250620-Pandas.cut
  • 伸缩线充电宝推荐丨倍思灵动充45W突破移动界限!
  • 基于YOLO的语义分割实战(以猪的分割为例)
  • 5G 浪潮:发展全景、困境突围与未来航向
  • 微软应用商店打不开怎么办2025,打开TLS1.3
  • 【Python】Excel表格操作:ISBN转条形码
  • 小程序注册失败怎么办/seo项目分析
  • 仿牌独立站/百度员工收入工资表
  • 北京网站设计公司/网络营销策划的内容
  • 白云做网站SEO/手机一键优化
  • 第三方做公司网站/宁波网站推广优化哪家正规
  • 想建网站/厦门人才网官网招聘信息网