当前位置: 首页 > 面试题库 >

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

宓英哲
2023-03-14
问题内容

考虑以下代码:

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


问题答案:

协议类型的值使用“现有容器”表示(请参见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<...>

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



 类似资料:
  • 问题内容: 在下面的代码中,我想测试是否为。如果是的话,我想作为。你怎么做到这一点?如果不使用强制转换,则使用其他技术。 那里的最后一行不会编译。错误是: 协议“ SpecialController”仅具有通用要求或关联类型要求,因此只能用作通用约束。 问题答案: 不幸的是,Swift当前不支持将具有关联类型的协议用作实际类型。但是,从技术上讲这对于编译器是可行的。并且很可能在该语言的未来版本中实

  • Clang和GCC都抱怨格式不正确,并给出了奇怪的诊断。 Clang报告 GCC报告 但是,根据expr.static.cast#4 如果存在从E到T的隐式转换序列([over.best.ics]),则表达式E可以显式转换为类型T 将一个类型转换为同一类型不是叫做标识转换吗? over.best.ics#General-8 如果不需要转换来将参数与参数类型匹配,则隐式转换序列是由标识转换([ove

  • 问题内容: 我对一方面用于协议的关联类型的语法和另一方面用于泛型类型的语法之间的区别感到困惑。 例如,在Swift中,可以使用以下方式定义通用类型 而使用诸如 为什么后者不只是: 是否有某种深层的原因(或者也许是显而易见的,对我来说就迷失了),原因是该语言未采用后一种语法? 问题答案: 在开发人员列表中已对此进行了多次讨论。基本答案是关联类型比类型参数更灵活。虽然您在这里有一个类型参数的特定情况,

  • 问题内容: 我正在使用泛型编写某些东西,令我惊讶的是,我发现这行不通: 那我不能实例化泛型吗?没有任何方法可以做到这一点吗? 问题答案: 是的,这真是令人讨厌。 我使用的解决方法是强制客户端在构造新类时传递类-即 然后您可以使用。

  • 问题内容: 如果P是类而不是协议,则代码可以正常工作。类和协议之间有什么区别?它们都被实现为堆中的指针,不是吗?上面的代码可以成功编译,但是在运行时崩溃。这个EXC_BAD_ACCESS错误是什么意思? 感谢@Antonio,但我仍然不了解此示例代码的工作方式。 AnyObject是特例吗? 参考:https : //developer.apple.com/library/content/docu

  • 这个问题是在泛型关联类型在Rust中可用之前提出的,尽管它们是被提出和开发的。 我的理解是,特征泛型和关联类型在它们可以绑定到结构的类型数量上有所不同。 关联类型仅绑定1个类型: 泛型关联类型是这两种类型的混合。它们绑定到一个类型,正好有一个关联的生成器,而生成器又可以关联任何数量的类型。那么前面示例中的和这个泛型关联类型有什么区别呢?