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

Swift基础 -- 3、协议和扩展、错误处理、范型

目录

  • 1、协议和扩展
  • 2、错误处理
  • 3、泛型

1、协议和扩展

使用 protocol来声明一个协议。

protocol ExampleProtocol {var simpleDescription: String { get }mutating func adjust()
}

类、枚举和结构体都可以遵循协议。

class SimpleClass: ExampleProtocol {var simpleDescription: String = "A very simple class."var anotherProperty: Int = 69105func adjust() {simpleDescription += "  Now 100% adjusted."}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescriptionstruct SimpleStructure: ExampleProtocol {var simpleDescription: String = "A simple structure"mutatingfunc adjust() {simpleDescription += " (adjusted)"}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription

练习: 给 ExampleProtocol增加一个要求。你需要怎么修改 SimpleClassSimpleStructure才能保证它们仍旧遵循这个协议?

注意在 SimpleStructure的声明中,使用了 mutating关键字来标记那些会修改结构体的方法。而 SimpleClass的声明中不需要将其方法标记为 mutating,因为类的方法总是可以修改类本身。

可以使用 extension为已有的类型添加新功能,比如新的方法和计算属性。扩展(extension)还可以为在其他地方声明的类型添加需要遵循的协议,包括那些从库或框架中导入的类型。

extension Int: ExampleProtocol {var simpleDescription: String {return "The number \(self)"}mutating func adjust() {self += 42}}
print(7.simpleDescription)
// 打印“The number 7”

练习: 给 Double类型写一个扩展,添加一个 absoluteValue属性。

你可以像使用其他命名类型一样使用协议名——例如,创建一个有不同类型但是都遵循同一个协议的对象集合。当你处理的是一个封装的协议类型时,协议外定义的方法不可用。

let protocolValue: any ExampleProtocol = a
print(protocolValue.simpleDescription)
// 打印“A very simple class.  Now 100% adjusted.”
// print(protocolValue.anotherProperty)  // 去掉注释可以看到错误

尽管变量 protocolValue的运行时类型是 SimpleClass,但编译器还是会将其视为 ExampleProtocol类型。这意味着你不能访问在协议之外的方法或者属性。

2、错误处理

你可以使用任何遵循 Error协议的类型来表示错误。

enum PrinterError: Error {case outOfPapercase noTonercase onFire
}

使用 throw来抛出错误,并使用 throws标记可能抛出错误的函数。如果在函数中抛出错误,函数会立即返回,并由调用该函数的代码来处理这个错误。

func send(job: Int, toPrinter printerName: String) throws -> String {if printerName == "Never Has Toner" {throw PrinterError.noToner}return "Job sent"
}

处理错误有多种方式,其中一种是使用 do-catch。在 do代码块中,你需要在可以抛出错误的代码前加上 try。在 catch代码块中,除非你另外命名,否则错误会被默认命名为 error

do {let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")print(printerResponse)
} catch {print(error)
}
// 打印“Job sent”

练习: 将 printer name 改为 "Never Has Toner",使 send(job:toPrinter:)函数抛出错误。

可以提供多个 catch块来处理特定的错误。和 switch 中 case的写法一样,在 catch后写匹配模式。

do {let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")print(printerResponse)
} catch PrinterError.onFire {print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {print("Printer error: \(printerError).")
} catch {print(error)
}
// 打印“Job sent”

练习: 在 do代码块中添加抛出错误的代码。你需要抛出哪种错误使其被第一个 catch块处理?对于第二个和第三个 catch块,又需要抛出哪种错误呢?

另一种处理错误的方式是使用 try?将结果转换为可选的。如果函数抛出错误,该错误会被抛弃并且结果为 nil。否则,结果会是一个包含函数返回值的可选值。

let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")

使用 defer代码块来表示在函数返回前,函数中最后执行的代码。无论函数是否会抛出错误,这段代码都将执行。使用 defer可以把初始化代码和扫尾代码写在一起,即使它们在不同的时机执行。

var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]func fridgeContains(_ food: String) -> Bool {fridgeIsOpen = truedefer {fridgeIsOpen = false}let result = fridgeContent.contains(food)return result
}
if fridgeContains("banana") {print("Found a banana")
}
print(fridgeIsOpen)
// 打印“false”

3、泛型

在尖括号里写一个名字来创建一个泛型函数或者泛型类型。

func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {var result: [Item] = []for _ in 0..<numberOfTimes {result.append(item)}return result
}
makeArray(repeating: "knock", numberOfTimes: 4)

你可以为函数和方法创建泛型,也可以为类、枚举和结构体创建泛型。

// 重新实现 Swift 标准库中的可选类型
enum OptionalValue<Wrapped> {case nonecase some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)

在代码主体之前使用 where来指定对类型的一系列要求——例如,要求类型实现特定协议,要求两个类型是相同的,或者要求某个类具有特定的父类。

func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> BoolwhereT.Element: Equatable, T.Element == U.Element
{for lhsItem in lhs {for rhsItem in rhs {if lhsItem == rhsItem {returntrue}}}returnfalse
}
anyCommonElements([1, 2, 3], [3])

练习: 修改 anyCommonElements(_:_:)函数,使其返回一个数组,该数组包含任意两个序列中共有的元素。

<T: Equatable><T> ... where T: Equatable的写法是等价的。

http://www.dtcms.com/a/283343.html

相关文章:

  • 宇树 G1 部署(七)——系统重装与镜像还原
  • 第13章 AB实验平台的建设
  • Redis原理和应用以及整合SpringBoot+Vue
  • RAG优化秘籍:基于Tablestore的知识库答疑系统架构设计
  • 智能体架构深度解构:一次用户请求的完整旅程
  • 多维动态规划题解——最小路径和【LeetCode】空间优化一维数组
  • Java设计模式之-组合模式
  • Fiddler 中文版 API 调试与性能优化实践 官方中文网全程支持
  • 怎么删除 wps 的右键菜单
  • Android-EDLA【CTS】CtsMediaRecorderTestCases存在fail
  • 初等数论简明教程
  • watermark的作用
  • 剑指offer63_扑克牌的顺子
  • 如何加快golang编译速度
  • Cursor区域限制问题解决方案:AI模型访问技术突破与环境隔离实践
  • 如何在硬件中进行有效地调试
  • SIMATIC HMIWinCC UnifiedPerformance Insight - 使用 KPI 优化流程
  • 冰岛人(map)
  • Java破解零工市场“真需求”
  • Day04_C语言网络编程20250716
  • 认识ETL流程:数据工程的基石
  • 暑期自学嵌入式——Day04(C语言阶段)
  • 深度学习中的注意力机制:原理、应用与实践
  • 【Linux】如何使用nano创建并编辑一个文件
  • 暑期算法训练.2
  • PHP8.5.0 Alpha 1 正式发布!
  • 1_需求规格编写提示词_AI编程专用简化版
  • 华为OD机试_2025 B卷_完美走位(Python,100分)(附详细解题思路)
  • mongodb操作巨鹿
  • 9.IEnumerable可枚举接口 C#例子 WPF例子