一、错误(异常)
1. Swift 我们定义异常需要怎么做?
- Swift 中可以通过
Error
协议自定义运行时的错误信息
enum SomeError : Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
2. 函数内部如何抛出错误?函数声明要加上什么?
- 函数内部通过
throw
抛出自定义 Error
- 可能会抛出
Error
的函数必须加上 throws
声明
func divide(_ num1: Int, _ num2: Int) throws -> Int {
if num2 == 0 {
throw SomeError.illegalArg("0 不能做为除数")
}
return num1 / num2
}
3. 如何调用一个有错误抛出的函数?
var result1 = try divide(100, 0);
var result2 = try? divide(100, 0);
var result3 = try! divide(100, 0);
4. 如何捕捉错误?错误爆出,会影响后续代码的执行吗?
- 使用
do-catch
捕捉错误
- 抛出
Error
后,try
下一句直到作用域结束
的代码都将停止运行
func test() {
print("1")
do {
print("2")
print(try divide(100, 0))
print("3")
} catch let SomeError.illegalArg(msg) {
print("参数异常:", msg)
} catch let SomeError.outOfBounds(size, index) {
print("下标越界:", size, index)
} catch SomeError.outOfMemory {
print("内存溢出")
} catch {
print("未知错误")
}
print("4")
}
- 上述代码将打印
1 2 参数异常:0不能作为除数 4
5. try?、try!
处理错误的时候和 try
有什么不同?
- 可以使用
try?、try!
调用可能会抛出 Error
的函数,这样就不需要去处理 Error
func test2() {
print("1")
var result1 = try? divide(20, 10) // Optional(2), Int?
var result2 = try? divide(20, 0) // nil, Int?
var result3 = try! divide(20, 10) // 2, Int
}
6. defer 关键字有什么用?举一个实际例子说明?
-
defer
语句:用来定义以任何方式(抛错误、return 等
)离开代码块
前必须要执行
的代码
-
defer
语句将延迟至当前作用域结束之前执行
defer
二、泛型(Generics)
1. 泛型(Generics)这个技术出现的目的是什么?
泛型
2. 思考下面代码,红框内的 <T>
可以省略掉吗?
示例
- 不能省略掉,省略之后就是
普通函数
了,编译器会认为 T 是一个自定义类型
,如果找不到 T 的定义,就会编译报错
3. 思考为什么下列代码中,不需要像声明函数一样,加上 T 的类型说明?
示例
- 因为调用函数的时候当
i1
传入的时候,编译器就可以确认 T
的类型,所以无需额外说明
- 总结:
就是要有办法让编译器在调用之时能确定 T 的类型
4. 我们声明 func
中泛型的时候一般用什么字母表示,我们声明 class 中的泛型的时候一般用什么字母表示,分别代表什么?
-
func
中泛型的时候一般用 T
,表示 Type
-
class
中泛型的时候一般用 E
,表示 Element
class 中使用泛型
5. 泛型在 Class、Enum、Struct 中(了解)
示例
6.思考泛型的本质是什么呢?或者说实现原理?
- 在 C++中,编译器会根据代码需要,给泛型生成多个函数
C++的做法
- 当需要 Int 类型的泛型函数时,会生成
注释 1 的函数
- 当需要 Double 类型的泛型函数时,会生成
注释 2 的函数
-
那么在 Swift 中采取的做法是否和 C++一样呢?
Int 的 swapValues 函数调用地址
Double 的swapValues 函数调用地址
- 对比发现,两次调用的函数地址都一样,说明 Swift 采取的做法和 C++是不同的。
Swift 的做法
- 可以发现,Swift 将参数的
type metadata
当成函数传入了 callq
中
- Swift 是将
type metadata
作为函数的依据,来区别对待传入的泛型
7. 如果想在协议中使用泛型怎么做?
- 我们之前学过的泛型都是用在
类、结构体、枚举、函数
中
- 在协议中想要使用泛型,需要使用
关联类型(associated type)
技术
关联类型
8. 如果想对泛型进行约束要怎么做?(了解即可)
泛型约束
网友评论