Rap*_*ael 2 casting typechecking associated-types swift swift-protocols
考虑这段代码:
extension Collection {
func foo() -> Int {
if self.first is Collection {
return (self.first as! Collection).underestimatedCount // ERROR
}
else {
return self.underestimatedCount
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们得到了令人恐惧且明显令人困惑的情况:
协议“Collection”只能用作通用约束,因为它具有 Self 或关联的类型要求。
然而,这很高兴编译:
func foo<C: Collection>(_ c: C) -> Int where C.Iterator.Element: Collection {
if let first = c.first {
return first.underestimatedCount // *
} else {
return c.underestimatedCount
}
}
Run Code Online (Sandbox Code Playgroud)
为什么?!
特别是,编译器不知道关联*
类型(的类型)first
是如何实现的;它只得到了它们已经得到的承诺(因为任何类型的对象都Collection
必须实现它们)。第一个示例中也有同样的保证!那么为什么编译器会抱怨其中之一而不是另一个呢?
我的问题是:在 line 处*
,编译器知道什么是它不 in line 的ERROR
?
协议类型的值使用“存在容器”表示(请参阅有关它们的精彩 WWDC 演讲;或在 Youtube 上),它由固定大小的值缓冲区组成,用于存储值(如果值大小超过(它会在堆上分配),一个指向协议见证表的指针,以便查找方法实现,以及一个指向值见证表的指针,以便管理值的生命周期。
\n\n非专用泛型使用几乎相同的格式(我在本问答中更深入地讨论了这一点) \xe2\x80\x93 当它们被调用时,指向协议和值见证表的指针被传递给函数,并且值本身使用值缓冲区本地存储在函数内部,该缓冲区将为大于该缓冲区的值进行堆分配。
\n\n因此,由于它们的实现方式完全相似,我们可以得出这样的结论:无法使用具有泛型之外的关联类型或约束的协议进行对话Self
只是该语言当前的限制。没有真正的技术原因说明它不可能,只是还没有实现。
以下是关于“广义存在主义”的泛型宣言的摘录,其中讨论了这在实践中如何运作:
\n\n\n\n\n对存在类型的限制来自于实现限制,但允许协议类型的值是合理的,即使协议具有自约束或关联类型。例如,
\n\nIteratorProtocol
再次考虑如何将其用作存在主义:Run Code Online (Sandbox Code Playgroud)\n\nprotocol IteratorProtocol {\n associatedtype Element\n mutating func next() -> Element?\n}\n\nlet it: IteratorProtocol = ...\nit.next() // if this is permitted, it could return an "Any?", i.e., the existential that wraps the actual element\n
此外,想要约束存在性的关联类型是合理的,例如,“
\n\nSequence
元素类型为String
”的元素可以通过将 where 子句放入\nprotocol<...>
或Any<...>
(根据“重命名protocol<...>
为Any<...>
”)来表达:Run Code Online (Sandbox Code Playgroud)\n\nlet strings: Any<Sequence where .Iterator.Element == String> = ["a", "b", "c"]\n
前导
\n.
表明我们正在讨论动态类型,即Self
符合协议的类型。Sequence
我们没有理由不支持.where
Any<...>
从能够将值作为具有关联类型的协议键入开始,只需一小步即可允许类型转换为给定类型,从而允许编译第一个扩展之类的内容。
\n