首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何使用泛型类似数组的属性创建协议

如何使用泛型类似数组的属性创建协议
EN

Stack Overflow用户
提问于 2020-08-05 00:18:36
回答 1查看 189关注 0票数 0

我正在创建一个协议来抽象不同的模型(手工制作的、可解码的和节俭生成的),如下所示:

代码语言:javascript
运行
复制
protocol FeedItemModeling {
    var text: String? { get }
    var url: URL? { get }
}

protocol FeedModeling {
    var items: [FeedItemModeling]? { get }
}

这将工作得很好,除非节俭模型不使用基本的数组,而是一个符合RandomAccessCollectionTList。由于ArrayTList都符合RandomAccessCollection,因此我尝试将协议定义更改为:

尝试A)

代码语言:javascript
运行
复制
var items: RandomAccessCollection<FeedItemModeling>? { get }

这给出了错误:“无法专门化非泛型类型‘RandomAccessCollection’”。我认为这是因为associatedtype是一个不成熟的泛型,因为它可以在协议本身内部强制执行约束,但不会在外部公开;这意味着在我们的例子中,RandomAccessCollectionassociatedtypesRandomAccessCollection中解析,但FeedModeling没有办法访问它?

尝试B)

代码语言:javascript
运行
复制
var items: RandomAccessCollection? { get }

给出了“协议'RandomAccessCollection‘只能用作泛型约束,因为它有自身或关联的类型要求”,并且无论如何都会失去对FeedItemModeling的约束。

尝试C)

代码语言:javascript
运行
复制
associatedtype C: RandomAccessCollection
var items: C? { get }

工作,但我们失去了对FeedItemModeling的约束,所以这是不可接受的。

尝试D)

代码语言:javascript
运行
复制
associatedtype C: RandomAccessCollection
var items: C<FeedItemModeling>? { get }

给出“无法专门化非泛型类型‘Self.c’。”我想也是因为上面的原因吧?

尝试E)

代码语言:javascript
运行
复制
associatedtype C<E>: RandomAccessCollection where E: FeedItemModeling
var items: C? { get }

给出了“关联的类型不能有泛型参数列表”。我假设这是因为现在约束上有一个约束,它不能用这种方式表达?

尝试F)

代码语言:javascript
运行
复制
typealias C<E> = RandomAccessCollection
var items: C<FeedItemModeling>? { get }

给出:“协议'RandomAccessCollection‘只能用作泛型约束,因为它有自身或关联的类型要求”。同样的原因?

尝试G)

代码语言:javascript
运行
复制
associatedtype FeedItemModelingList = RandomAccessCollection where RandomAccessCollection.Element: FeedItemModeling
var items: FeedItemModelingList? { get }

给出了“关联类型‘元素’只能与具体类型或泛型参数一起使用”。我不明白这个,请告诉我为什么?

尝试H)

代码语言:javascript
运行
复制
protocol FeedItemModelingList: RandomAccessCollection {}
...
var items: FeedItemModelingList? { get }

给出:“协议'FeedItemModelingList‘只能用作泛型约束,因为它有自身或关联的类型要求”。

尝试I)

代码语言:javascript
运行
复制
protocol FeedItemModelingList: RandomAccessCollection where Element == FeedItemModeling {}
...
associatedtype L = FeedItemModelingList
var items: L? { get }

看起来(到目前为止)还不错,但实际上很难看。

还有更好的主意吗?

EN

回答 1

Stack Overflow用户

发布于 2020-10-10 11:42:19

我想你想要的是

代码语言:javascript
运行
复制
protocol FeedItemModeling {
    var text: String? { get }
    var url: URL? { get }
}

protocol FeedModeling {
    associatedtype TList: RandomAccessCollection where TList.Element == FeedItemModeling
    var items: TList? { get }
}

至于你的问题:

我认为这是因为关联类型是一个半生不熟的泛型

我认为在现代Swift中,关联类型与泛型非常接近,尽管两者都有些不完整,特别是在现有类型方面,尽管它每年都在变得更好。一条经验法则是许多Swift通用/PAT问题都是用where解决的。

给出了“不能专门化非泛型类型‘self.c’”。我想也是因为上面的原因吧?

IMO这个错误相当糟糕,但它基本上是关于<>的语法问题,它只允许泛型类型,而不允许协议。“专门化”在Swift社区中是一个有点过载的术语,可以表示从类型约束到为已知类型参数值发出机器代码的任何东西。

给出了“关联类型不能有泛型参数列表”。我假设这是因为现在约束上有一个约束,它不能用这种方式表达?

您可以表达对约束的约束,但是没有类似于rust的<F=A>语法yet。目前,您需要where

只能用作泛型约束,因为它具有自身或关联的类型要求。

这就是臭名昭著的"PAT“或”广义存在“问题(参见泛型宣言)。每个人都很恼火,希望有一天我们会支持它。

“关联类型'Element‘只能与具体类型或泛型参数一起使用”。我不明白这个,请告诉我为什么?

RandomAccessCollection只是一种协议,你碰巧在附近使用过,但斯威夫特不知道其中的联系。所以当你这么说的时候

代码语言:javascript
运行
复制
associatedtype FeedItemModelingList = RandomAccessCollection where RandomAccessCollection.Element: FeedItemModeling

有点像你做的那样

代码语言:javascript
运行
复制
func foo() where Collection.Element == String

在这种情况下,Collection.Element是“封闭的”,没有办法对它进行专门化或给它一个约束。相反,你需要约束一些开放的东西,比如你声明的关联类型。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63251024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档