为什么要在 Swift RandomAccessCollection 协议中重新定义 Element 类型?

Why redefine the Element type in Swift RandomAccessCollection protocol?

提问人:ximmyxiao 提问时间:11/17/2023 最后编辑:ximmyxiao 更新时间:11/17/2023 访问量:48

问:

从源代码

public protocol RandomAccessCollection<Element> : BidirectionalCollection where Self.Indices : RandomAccessCollection, Self.SubSequence : RandomAccessCollection {

    associatedtype Element

我们可以看到定义了 to associatedtype。这种重新定义的含义是什么?RandomAccessCollectionElement

而Array是符合这个协议的。来自 Array 的源代码RandomAccessCollection

@frozen public struct Array<Element> {
...

}

也会有一个。Element

这 3 个元素之间有什么联系吗?

迅速

评论


答:

3赞 Sweeper 11/17/2023 #1

RandomAccessCollection不需要重新声明 from。删除声明不会破坏任何内容或向代码添加任何新功能。ElementBidirectionalCollection

protocol Foo<T> {
    associatedtype T
}

protocol Bar<T>: Foo {
    associatedtype T
}

编译为与以下内容完全相同的内容:

protocol Foo<T> {
    associatedtype T
}

protocol Bar<T>: Foo {

}

godbolt.org 试试这个!

我能看到的唯一区别是生成的文档。通过重新定义 ,RandomAccessCollection.Element 和 BidirectionalCollection.Element 有单独的页面,直接从 和 的页面链接。ElementRandomAccessCollectionBidirectionalCollection

如果不重新声明,则不太明显具有关联类型,因为您必须转到“继承自”部分并转到声明的协议才能看到它确实具有关联类型。ElementRandomAccessCollectionElementElementElement

也就是说,你可以争辩说,你可以通过在其声明中看到它的主要关联类型来立即推断出具有关联类型:RandomAccessCollectionElementElement

protocol RandomAccessCollection<Element>

但是在旧版本的 Swift 中并不存在主要的关联类型,因此作者最初这样做仍然是有道理的。此外,重新声明的不仅仅是 .还有、、等。RandomAccessCollectionElementIndexSubSequence

通过重新声明关联的类型,在阅读文档时,协议需要什么类型一目了然。

此外,还可以在每个关联的类型声明上编写不同的文档文本。

protocol Foo<T> {
    /// something describing T...
    associatedtype T
}

protocol Bar<T>: Foo {
    /// something describing T that is more specific to Bar...
    associatedtype T
}

至于 in ,这是一个泛型类型参数,实现了 (和许多其他协议)的相关类型要求。它本身不是关联的类型声明。ElementArray<Element>RandomAccessCollection

评论

0赞 ximmyxiao 11/20/2023
谢谢@Sweerper,我仍然对这种“主要关联类型”的方式感到疯狂。我可以这样理解整个事情吗:当我们创建一个 Array 对象时,这个对象将符合 RandomAccessCollection 协议,而 RandomAccessCollection 需要一个 Element 关联类型,将从数组的源代码中获取该关联类型的特定元素类型(感谢编译器的类型推断)。因此,我们可以省略 Array 源代码中的 typealias
0赞 Sweeper 11/20/2023
@ximmyxiao 主要关联类型实际上与此没有任何关系。如果不是主要的关联类型,我的答案仍然相同。关联的类型要求仅要求符合的类型具有具有特定名称的类型。在这种情况下,要求其符合者具有名为 的类型。 确实有这样一个类型 - 它恰好是它的泛型类型参数。ElementRandomAccessCollectionElementArray
0赞 Sweeper 11/20/2023
@ximmyxiao 类型别名通常用于满足关联的类型约束,因为它们是声明具有特定名称的类型并使其与现有类型相同的简单方法。但是还有其他方法可以声明类型,例如声明泛型类型参数,或声明嵌套的结构/类/枚举等。所有关联的类型要求都需要成为有效类型,其中是符合的类型。C.ElementC
0赞 Sweeper 11/20/2023
@ximmyxiao如果您仍然感到困惑,我建议您发布一个新问题。
0赞 ximmyxiao 11/22/2023
,我知道我的理解错了哪里,我曾经认为 Array 中的 Element 和 RandomAccessCollection 中的 Element 是两回事。但是写完一个demo后发现它们都是一回事,如果用e元素(like:String)创建一个Array,RandomAccessCollection的Element也会是String。因为 RandomAccessCollection 是一个协议,它没有存储(或类似的东西)。因此,当我们在 Array 中设置 Element 时,这意味着我们也为 RandomAccessCollection 设置了 Element