考虑以下代码:
extension Collection { func foo() -> Int { if self.first is Collection { return (self.first as! Collection).underestimatedCount // ERROR } else { return self.underestimatedCount } } }
我们感到恐惧,而且显然令人费解:
协议“集合”具有自定义或相关类型要求,因此只能用作通用约束。
但是,这很容易编译:
func foo<C: Collection>(_ c: C) -> Int where C.Iterator.Element: Collection { if let first = c.first { return first.underestimatedCount // * } else { return c.underestimatedCount } }
为什么?!
特别是,编译器 不 知道*如何关联的类型(类型)的first已经实现; 它只能得到它们已经存在的 承诺 (因为任何类型的对象Collection 都 必须实现它们)。第一个示例中也有同样的保证!那么,为什么编译器抱怨一个而不是另一个呢?
*
first
Collection
我的问题是:在代码行中*,编译器如何知道它不在代码行中ERROR?
ERROR
协议类型的值使用“现有容器”表示(请参见WWDC上有关它们的详细论述;或在Youtube上),该容器由固定大小的值缓冲区组成,以便存储该值(如果值大小超过此值, (它将分配),指向协议见证表的指针以查找方法实现,以及指向值见证表的指针以管理值的生存期。
非专业泛型使用几乎相同的格式(在本问答中我会更深入地介绍这种格式)–调用它们时,将协议和值见证表的指针传递给函数,并且值本身存储在内部该函数使用值缓冲区,该缓冲区将为大于该缓冲区的值堆分配。
因此,由于这些实现方式的巨大相似性,我们可以得出这样的结论,即不能根据具有关联类型或Self泛型之外的约束的协议进行交谈只是该语言的当前限制。没有真正的技术原因无法实现,只是尚未实现。
Self
以下是泛型宣言中的“ 广义存在论”摘录,其中讨论了这在实践中如何工作:
对存在类型的限制来自实现限制,但是即使协议具有自我约束或关联类型,也可以允许协议类型的值是合理的。例如,IteratorProtocol再次考虑一下,以及如何将其用作存在对象: protocol IteratorProtocol { associatedtype Element mutating func next() -> Element? } let it: IteratorProtocol = ... it.next() // if this is permitted, it could return an "Any?", i.e., the existential that wraps the actual element 此外,合理地限制一个存在性的关联类型,例如,可以通过将where子句放入或(按“重命名为”)来表示“ Sequence元素类型为 String”的a :protocol<...>``Any<...>``protocol<...>``Any<...> let strings: Any<Sequence where .Iterator.Element == String> = ["a", “b”, “c”] 前导.表明我们正在谈论动态类型,即Self符合Sequence协议的类型。没有理由不能支持。中的任意where子句Any<...>。
对存在类型的限制来自实现限制,但是即使协议具有自我约束或关联类型,也可以允许协议类型的值是合理的。例如,IteratorProtocol再次考虑一下,以及如何将其用作存在对象:
IteratorProtocol
protocol IteratorProtocol { associatedtype Element mutating func next() -> Element? } let it: IteratorProtocol = ... it.next() // if this is permitted, it could return an "Any?", i.e.,
the existential that wraps the actual element
此外,合理地限制一个存在性的关联类型,例如,可以通过将where子句放入或(按“重命名为”)来表示“ Sequence元素类型为 String”的a :protocol<...>``Any<...>``protocol<...>``Any<...>
Sequence
String
protocol<...>``Any<...>``protocol<...>``Any<...>
let strings: Any<Sequence where .Iterator.Element == String> = ["a",
“b”, “c”]
前导.表明我们正在谈论动态类型,即Self符合Sequence协议的类型。没有理由不能支持。中的任意where子句Any<...>。
.
where
Any<...>
从能够将值作为具有关联类型的协议来输入协议,这只是很短的一步,即允许将类型强制转换为给定类型,从而允许编译诸如您的第一个扩展名之类的东西。