Swift:是否可以在协议中添加协议扩展?(Swift: Is it possible to add a protocol extension to a protocol?)

编程入门 行业动态 更新时间:2024-10-24 02:31:52
Swift:是否可以在协议中添加协议扩展?(Swift: Is it possible to add a protocol extension to a protocol?)

可以说我有两个协议:

protocol TheirPcol {} protocol MyPcol { func extraFunc() }

我想要做的是为'TheyPcol'创建一个协议扩展,让extraFunc()可以处理符合'TheyPcol'的任何东西。 所以这样的事情:

extension TheirPcol : MyPcol { // Error 'Extension of protocol 'TheirPcol' cannot have an inheritance clause. func extraFunc() { /* do magic */} } struct TheirStruct:TheirPcol {} let inst = TheirStruct() inst.extraFunc()

这方面的问题是'TheyPcol','TheirStruct'都是由我无法控制的外部API处理的。 所以我传递了实例'inst'。

可以这样做吗? 或者我将不得不做这样的事情:

struct TheirStruct:TheirPcol {} let inst = TheirStruct() as! MyPcol inst.extraFunc()

Lets say I have two protocols:

protocol TheirPcol {} protocol MyPcol { func extraFunc() }

What I want to do is to create a protocol extension for 'TheirPcol' which lets extraFunc() work on anything which conforms to 'TheirPcol'. So something like this:

extension TheirPcol : MyPcol { // Error 'Extension of protocol 'TheirPcol' cannot have an inheritance clause. func extraFunc() { /* do magic */} } struct TheirStruct:TheirPcol {} let inst = TheirStruct() inst.extraFunc()

The kicker in this is that 'TheirPcol', 'TheirStruct' are all handled by an external API which I do not control. So I'm passed the instance 'inst'.

Can this be done? Or am I going to have to do something like this:

struct TheirStruct:TheirPcol {} let inst = TheirStruct() as! MyPcol inst.extraFunc()

最满意答案

似乎有两个用例,说明为什么你可能想做你正在做的事情。 在第一个用例中,Swift将允许您执行您想要的操作,但在第二个用例中并不是非常干净。 我猜你属于第二类,但我会经历这两个类别。

扩展了TheirPcol的功能

您可能想要这样做的一个原因就是为TheirPcol提供额外的功能。 就像编译器错误所说的那样,你不能扩展Swift协议以符合其他协议。 但是,您可以简单地扩展TheirPcol 。

extension TheirPcol { func extraFunc() { /* do magic */ } }

在这里,您将为所有符合TheirPcol的对象提供方法extraFunc()并为其提供默认实现。 这完成了扩展符合TheirPcol的对象的功能的任务,如果您希望它也适用于您自己的对象,那么您可以将对象与TheirPcol 。 但是,在许多情况下,您希望将MyPcol作为主要协议,并将TheirPcol视为符合MyPcol 。 不幸的是,Swift目前不支持声明与其他协议一致的协议扩展。

使用TheirPcol对象就好像它们是MyPcol

在用例(很可能是你的用例)你确实需要单独存在MyPcol ,那么据我所知,没有干净的方法来做你想要的。 这里有一些有效但非理想的解决方案:

围绕他们的TheirPcol包装

一个潜在的混乱方法是拥有如下所示的struct或class :

struct TheirPcolWrapper<T: TheirPcol>: MyPcol { var object: T func extraFunc() { /* Do magic using object */ } }

理论上,您可以使用此结构作为转换的替代方法,如您的示例中所示,当您需要使现有对象实例符合MyPcol 。 或者,如果您有接受MyPcol作为通用参数的函数,您可以创建接受MyPcol等效函数,然后将其转换为TheirPcolWrapper并将其发送到TheirPcolWrapper中的其他函数。

另外需要注意的是,如果您传递的是TheirPcol的对象,那么在没有首先将其转换为显式类型的情况下,您将无法创建一个TheirPcolWrapper实例。 这是由于Swift的一些泛型限制。 所以,像这样的对象可能是另一种选择:

struct TheirPcolWrapper: MyPcol { var object: MyPcol func extraFunc() { /* Do magic using object */ } }

这意味着你可以在不知道你给出的TheirPcol的显式类型的情况下创建一个TheirPcolWrapper实例。

但是对于一个大型项目来说,这两个都可能非常快。

使用子协议扩展单个对象

另一个非理想的解决方案是扩展您知道符合TheirPcol每个对象,并且您知道您希望支持这些对象。 例如,假设您知道TheirPcol和TheirPcol符合TheirPcol 。 您可以创建MyPcol的子协议,然后显式声明两个对象的一致性,如下所示:

protocol BridgedToMyPcol: TheirPcol, MyPcol {} extension BridgedToMyPcol { func extraFunc() { // Do magic here, given that the object is guaranteed to conform to TheirPcol } } extension ObjectA: BridgedToMyPcol {} extension ObjectB: BridgedToMyPcol {}

不幸的是,如果您希望支持大量对象,或者您无法提前知道对象将是什么,则此方法会崩溃。 当你不知道你给出的TheirPcol的显式类型时,它也会成为一个问题,尽管你可以使用type(of:)来获得元类型。

关于Swift 4的说明

您应该查看条件一致性 ,接受包含在Swift 4中的提案。具体来说,此提案概述了具有以下扩展名的能力:

extension Array: Equatable where Element: Equatable { static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... } }

虽然这不是你所要求的,但在底部你会发现“考虑的替代品”,它有一个名为“扩展协议以符合协议”的子部分,这更像是你要做的事情。 它提供了以下示例:

extension Collection: Equatable where Iterator.Element: Equatable { static func ==(lhs: Self, rhs: Self) -> Bool { // ... } }

然后说明以下内容:

此协议扩展将使任何Equatable元素集合Equatable,这是一个可以很好地利用的强大功能。 引入协议扩展的条件一致性会加剧一致性重叠的问题,因为说上述协议扩展的存在意味着没有符合Collection的类型可以声明它自己与Equatable,条件或其他方式的一致性是不合理的。

虽然我意识到你并没有要求具备条件一致性的能力,但这是我在讨论扩展到符合其他协议的协议时最接近的事情。

It seems there are two use-cases of why you may want to do what you are doing. In the first use-case, Swift will allow you to do what you want, but not very cleanly in the second use-case. I'm guessing you fall into the second category, but I'll go through both.

Extending the functionality of TheirPcol

One reason why you might want to do this is simply to give extra functionality to TheirPcol. Just like the compiler error says, you cannot extend Swift protocols to conform to other protocols. However, you can simply extend TheirPcol.

extension TheirPcol { func extraFunc() { /* do magic */ } }

Here, you are giving all objects that conform to TheirPcol the method extraFunc() and giving it a default implementation. This accomplishes the task of extending functionality for the objects conforming to TheirPcol, and if you want it to apply to your own objects as well then you could conform your objects to TheirPcol. In many situations, however, you want to keep MyPcol as your primary protocol and just treat TheirPcol as conforming to MyPcol. Unfortunately, Swift does not currently support protocol extensions declaring conformance to other protocols.

Using TheirPcol objects as if they were MyPcol

In the use case (most likely your use case) where you really do need the separate existence of MyPcol, then as far as I am aware there is no clean way to do what you want yet. Here's a few working but non-ideal solutions:

Wrapper around TheirPcol

One potentially messy approach would be to have a struct or class like the following:

struct TheirPcolWrapper<T: TheirPcol>: MyPcol { var object: T func extraFunc() { /* Do magic using object */ } }

You could theoretically use this struct as an alternative to casting, as in your example, when you need to make an existing object instance conform to MyPcol. Or, if you have functions that accept MyPcol as a generic parameter, you could create equivalent functions that take in TheirPcol, then convert it to TheirPcolWrapper and send it off to the other function taking in MyPcol.

Another thing to note is if you are being passed an object of TheirPcol, then you won't be able to create a TheirPcolWrapper instance without first casting it down to an explicit type. This is due to some generics limitations of Swift. So, an object like this could be an alternative:

struct TheirPcolWrapper: MyPcol { var object: MyPcol func extraFunc() { /* Do magic using object */ } }

This would mean you could create a TheirPcolWrapper instance without knowing the explicit type of the TheirPcol you are given.

For a large project, though, both of these could get messy really fast.

Extending individual objects using a child protocol

Yet another non-ideal solution is to extend each object that you know conforms to TheirPcol and that you know you wish to support. For example, suppose you know that ObjectA and ObjectB conform to TheirPcol. You could create a child protocol of MyPcol and then explicitly declare conformance for both objects, as below:

protocol BridgedToMyPcol: TheirPcol, MyPcol {} extension BridgedToMyPcol { func extraFunc() { // Do magic here, given that the object is guaranteed to conform to TheirPcol } } extension ObjectA: BridgedToMyPcol {} extension ObjectB: BridgedToMyPcol {}

Unfortunately, this approach breaks down if there are a large number of objects that you wish to support, or if you cannot know ahead of time what the objects will be. It also becomes a problem when you don't know the explicit type of a TheirPcol you are given, although you can use type(of:) to get a metatype.

A note about Swift 4

You should check out Conditional conformances, a proposal accepted for inclusion in Swift 4. Specifically, this proposal outlines the ability to have the following extension:

extension Array: Equatable where Element: Equatable { static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... } }

While this is not quite what you are asking, at the bottom you'll find "Alternatives considered", which has a sub-section called "Extending protocols to conform to protocols", which is much more what you're trying to do. It provides the following example:

extension Collection: Equatable where Iterator.Element: Equatable { static func ==(lhs: Self, rhs: Self) -> Bool { // ... } }

Then states the following:

This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.

While I realize you're not asking for the ability to have conditional conformances, this is the closest thing I could find regarding discussion of protocols being extended to conform to other protocols.

更多推荐

本文发布于:2023-07-31 02:42:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1340551.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:协议   Swift   add   extension   protocol

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!