背景
Swift的类型系统意在帮助开发者在编译期间构建 稳定健壮的代码。但类型系统有时会给我们带来一些阻碍,当然也正是因为这些"阻碍",才有了稳定。
协议中的关联类型
下面是一个比较经典的情况
Collection
协议因为定义了associatedtype
,无法直接作为参数或者返回值
protocol Collection : Sequence {
associatedtype Element
}
至于为什么有associatedtype Element
就无法作为参数或者返回值,作为编译检查严格的Swift这里还是可以理解的,因为当我们使用这个关联类型的协议的时候,Element
具体类型是什么编译器无法得知,在调用对应方法时候也就没有了检查(无法确定类型),这是不被允许的。例如:
func test(c: Collection) {
c.first? // 编译器该怎么定义这个类型是什么呢?
}
将Collection
作为函数返回值同理
func test() -> Collection {
}
test().first? // 这到底是个什么类型
协议中的Self
Self
作为参数 不可行
除了协议中的关联类型associatedtype
,还有一种情况也会让协议无法作为参数和返回值
func test(l: Equatable, r: Equatable) -> Bool {
return l == r
}
Equatable
的定义中有Self
相关的函数
protocol Equatable {
static func == (lhs: Self, rhs: Self) -> Bool
}
这个也是比较容易理解的。虽然test函数中的l
r
都是Equatable,但是==
要求判断的是同一种具体类型,而这里的test函数可以传入任何两种类型
Self
作为返回值 可行
但如果是这种协议,它是能作为函数的返回值的
protocol Copyable {
func copy() -> Self
}
带有associatedtype
的协议,不管这个type作为协议中的函数还是返回值都无法直接在其他函数中使用
带有Self
的协议,如果Self
用作参数,无法在其他函数中直接使用,如果Self
作为返回值,可以在其他函数中直接使用
那么将Self
作为参数和返回值为啥会有区别呢?
联系前面编译检查严格的例子,这种协议在作为参数的时候,可能会直接调用到关于Self
的函数而让编译器不知所措,而作为返回值,我们无法直接使用到关于Self
这个类型的地方,而是相当于返回了一个具体的协议,编译器并不会觉得模棱两可