在 Swift 的世界中, 如果我们将协议称之为国王, 那么泛型则可以视作皇后, 所谓一山不容二虎, 当我们把这两者结合起来使用的时候, 似乎会遇到极大的困难. 那么是否有一种方法, 能够将这两个概念结合在一起, 以便让它们成为我们前进道路上的垫脚石, 而不是碍手碍脚的呢? 答案是有的, 这里我们将会使用到类型擦除 (Type Erasure) 这个强大的特性.
Protocol 'SpellDelegate' can only be used as a generic constraint because it has Self or associated type requirements
因为 swift 泛型还不支持逆变和协变也就不会有真的类型擦除, 而这里说的 "类型擦除" 是指: 利用一个具体实现的通用泛型类 (参看系统库的 AnySequence), 去包装具体实现了该泛型协议的类. 用以解决不能直接使用泛型协议进行变量定义的问题. 具体可以看这篇文章 https://realm.io/cn/news/altconf-hector-matos-type-erasure-magic/?hmsr=toutiao.io
那个 ppt 的代码看着不方便, 我就简化了一下:
- protocol Erasable {
- associatedtype DataType
- func foo(arg: DataType) -> DataType
- }
- class AnyErasable<EraseType>: Erasable {
- private var fooFunc: (EraseType) -> EraseType
- init<Inject: Erasable>(_ obj: Inject) where Inject.DataType == EraseType {
- fooFunc = obj.foo
- }
- func foo(arg: EraseType) -> EraseType {
- return fooFunc(arg)
- }
- }
- class MyEraseClass: Erasable {
- func foo(arg: Int) -> Int {
- return arg * 10
- }
- }
- class MyEraseDelegate<T> {
- var val: T
- // var delegate: Erasable -- 编译失败
- var delegate: AnyErasable<T>?
- init(_ val: T) {
- self.val = val
- }
- func doSomething() -> T {
- return (delegate?.foo(arg: val))!
- }
- }
- let test = MyEraseDelegate(35)
- test.delegate = AnyErasable(MyEraseClass())
- print("result: \(test.doSomething())") // 350
来源: http://www.bubuko.com/infodetail-2650869.html