一尘不染

为什么我们不能转换为具有关联类型的协议类型,但是使用泛型达到相同的效果?

swift

考虑以下代码:

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 必须实现它们)。第一个示例中也有同样的保证!那么,为什么编译器抱怨一个而不是另一个呢?

我的问题是:在代码行中*,编译器如何知道它不在代码行中ERROR


阅读 195

收藏
2020-07-07

共1个答案

一尘不染

协议类型的值使用“现有容器”表示(请参见WWDC上有关它们的详细论述;或在Youtube上),该容器由固定大小的值缓冲区组成,以便存储该值(如果值大小超过此值,
(它将分配),指向协议见证表的指针以查找方法实现,以及指向值见证表的指针以管理值的生存期。

非专业泛型使用几乎相同的格式(在本问答中我会更深入地介绍这种格式)–调用它们时,将协议和值见证表的指针传递给函数,并且值本身存储在内部该函数使用值缓冲区,该缓冲区将为大于该缓冲区的值堆分配。

因此,由于这些实现方式的巨大相似性,我们可以得出这样的结论,即不能根据具有关联类型或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<...>

从能够将值作为具有关联类型的协议来输入协议,这只是很短的一步,即允许将类型强制转换为给定类型,从而允许编译诸如您的第一个扩展名之类的东西。

2020-07-07