考虑以下代码:
extension Collection {
func foo() -> Int {
if self.first is Collection {
return (self.first as! Collection).underestimatedCount // ERROR
}
else {
return self.underestimatedCount
}
}
}
我们感到害怕,显然令人费解:
协议'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
}
}
为什么?!
特别是,编译器不知道*
如何实现first
的相关类型({1}};它只获得它们已经存在的 promise (因为Collection
类型的任何对象都有来实现它们)。在第一个例子中也有同样的保证!那么为什么编译器会抱怨一个而不是另一个呢?
我的问题是:在第*
行,编译器知道它不在行ERROR
中?
答案 0 :(得分:3)
协议类型的值使用'存在容器'表示(请参阅this great WWDC talk;或on Youtube),它由固定大小的值缓冲区组成,以便存储值(如果值大小超过这个值,它将堆分配),指向协议见证表的指针,以便查找方法实现和指向值见证表的指针,以便管理值的生命周期。
非专用泛型使用几乎相同的格式(我稍稍深入in this Q&A) - 当它们被调用时,指向协议和值见证表的指针被传递给函数,值本身使用值缓冲区本地存储在函数内部,值缓冲区将为大于该缓冲区的值进行堆分配。
因此,由于这些实现方式的相似性,我们可以得出这样的结论:无法用相关类型的协议进行讨论,或者在泛型之外的Self
约束仅仅是当前的限制。语言。没有真正的技术原因,为什么它不可能,它还没有实现(还)。
以下是关于“Generalized existentials”的泛型宣言的摘录,其中讨论了如何在实践中发挥作用:
对存在类型的限制来自实施 限制,但允许协议类型的值是合理的 即使协议具有自我约束或相关类型。对于 例如,再次考虑
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
此外,想要约束相关联是合理的 存在性的类型,例如,元素类型为“a
Sequence
String
“可以通过将where子句放入其中来表达protocol<...>
或Any<...>
(每次“重命名protocol<...>
至Any<...>
”):let strings: Any<Sequence where .Iterator.Element == String> = ["a", "b", "c"]
前导
.
表示我们正在讨论动态类型, 即,符合Self
协议的Sequence
类型。 我们没有理由不支持其中的任意where
条款Any<...>
。
由于能够将值键入为具有关联类型的协议,因此只允许对该给定类型进行类型转换,这样就可以实现类似第一个扩展的编译。