- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
考虑这段代码:
extension Collection {
func foo() -> Int {
if self.first is Collection {
return (self.first as! Collection).underestimatedCount // ERROR
}
else {
return self.underestimatedCount
}
}
}
我们得到了可怕的和显然广泛令人费解的:
protocol 'Collection' can only be used as a generic constraint because it has Self or associated type requirements.
然而,这愉快地编译:
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
的相关类型(的类型)是如何实现的;它只会得到它们曾经存在的 promise (因为Collection
类型的任何对象必须 实现它们)。第一个例子中也有同样的保证!那么,为什么编译器会提示一个而不是另一个呢?
我的问题是:在 *
行,编译器知道什么它不在 ERROR
行?
最佳答案
协议(protocol)类型值使用“存在容器”表示(参见 this great WWDC talk ;或 on Youtube ),它由固定大小的值缓冲区组成,以便存储值(如果值大小超过这个,它会堆分配),一个指向协议(protocol)见证表的指针,以便查找方法实现和一个指向值见证表的指针,以便管理值的生命周期。
非专用泛型使用几乎相同的格式(我稍微深入一点 in this Q&A )——当它们被调用时,指向协议(protocol)和值见证表的指针被传递给函数,值本身是使用值缓冲区本地存储在函数内部,它将堆分配大于该缓冲区的值。
因此,由于它们的实现方式非常相似,我们可以得出结论,无法根据具有关联类型的协议(protocol)或 Self
进行对话。泛型之外的约束只是语言的当前限制。没有真正的技术原因说明它不可能,只是尚未实现(尚未)。
以下是关于“Generalized existentials”的泛型声明的摘录,其中讨论了这在实践中如何运作:
The restrictions on existential types came from an implementation limitation, but it is reasonable to allow a value of protocol type even when the protocol has Self constraints or associated types. For example, consider
IteratorProtocol
again and how it could be used as an existential: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 elementAdditionally, it is reasonable to want to constrain the associated types of an existential, e.g., "a
Sequence
whose element type isString
" could be expressed by putting a where clause intoprotocol<...>
orAny<...>
(per "Renamingprotocol<...>
toAny<...>
"):let strings: Any<Sequence where .Iterator.Element == String> = ["a", "b", "c"]
The leading
.
indicates that we're talking about the dynamic type, i.e., theSelf
type that's conforming to theSequence
protocol. There's no reason why we cannot support arbitrarywhere
clauses within theAny<...>
.
从能够将值键入为具有关联类型的协议(protocol),到允许类型转换为给定类型并因此允许像您的第一个扩展这样的东西进行编译只是一小步。
关于swift - 为什么我们不能转换为具有关联类型的协议(protocol)类型,而是使用泛型达到相同的效果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41695792/
我是一名优秀的程序员,十分优秀!