Swift - 使用通用方法为不同的 <T> 类型实现协议

问题描述

我有一个 Client 协议,如下所示:

protocol Client {
  func get<T>(_ url: String) -> Promise<T>
}

现在,当我尝试实施它时,问题就开始了。我想要两种类型的客户端:AlamofireClient 和 MockClient(未来可能更多,比如 ErrorClient 等,但让我们从简单开始)

所以我需要类似的东西:

final class AlamofireClient: Client {
   func get<T: Decodable>(_ url: String) -> Promise<T> {
        (...)
   }
}

和:

final class MockClient: Client {
   func get<T: Mockable>(_ url: String) -> Promise<T> {
            return Promise { seal in
               seal.fulfill(T.mock())
        }
   }
}

这里是应用程序中每个实体都将实现的简单 Mockable 接口:

public protocol Mockable {
    static func mock() -> Self
}

但我总是收到错误:

Type 'MockClient' does not conform to protocol 'Client'
Type 'AlamofireClient' does not conform to protocol 'Client'

那是因为与

不一样

有没有优雅的方法来解决这个问题?我无法为这个问题找到一个优雅的解决方案。也许整个想法很糟糕?我也尝试用 PAT 解决这个问题,但也没有运气。

解决方法

按照您编写的方式,通过遵守协议 Client,您必须实现一个函数 get,它带有一个通用的、不受约束的参数 T。在提供的示例实现中,您向泛型参数 T 添加了类型约束,该参数与协议中的函数不匹配。

解决此问题的方法不止一种。请记住,您说过所有实体都将符合 Mockable,需要对您提供的代码进行最少更改的解决方案是使用协议组合来强制所有参数 T 符合 {{1} }} 和 Decodable

Mockable

在您的客户端中,您将完全按照所写的方式实现该功能。

现在,在您的 protocol Client { func get<T: Decodable & Mockable>(_ url: String) -> Promise<T> } 中,您可以调用 MockClient,并且在您的实际实现中,您可以根据需要将 T.mock() 视为 T。当然,这现在要求即使您的模拟参数符合 Decodable,但我认为您的模拟参数将相当轻量级,因此这不会成为问题。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...