简体   繁体   English

Swift - 用通用方法实现不同的协议<t>类型</t>

[英]Swift - implement protocol with generic method for different <T> types

I have a Client protocol that looks like this:我有一个看起来像这样的Client协议:

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

Now, the problems start when I try to implement it.现在,当我尝试实现它时,问题就开始了。 I want to have 2 types of clients: AlamofireClient and MockClient (maybe in the future more, like ErrorClient etc. but let's start simple)我想要两种类型的客户端:AlamofireClient 和 MockClient(也许将来会更多,比如 ErrorClient 等,但让我们从简单的开始)

so I need something like:所以我需要类似的东西:

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

and:和:

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

here the simple Mockable interface that every entity in the app will implement:这里是应用程序中每个实体都将实现的简单 Mockable 接口:

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

But I always get the error:但我总是得到错误:

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

That's because is not the same as <T: Decodable> and <T: Mockable>那是因为与 <T: Decodable> 和 <T: Mockable> 不一样

Is there an elegant way to solve this issue?有没有一种优雅的方法来解决这个问题? I'm not able to find an elegant solution for this problem.我无法为这个问题找到一个优雅的解决方案。 Maybe the whole idea is just bad?也许整个想法很糟糕? I also tried solving the problem with PATs but also no luck there.我也尝试用 PAT 解决问题,但也没有运气。

The way you have it written, by conforming to the protocol Client, you have to implement a function get , with a generic, unconstrained argument T .您编写它的方式,通过遵守协议客户端,您必须实现一个 function get ,并带有一个通用的、不受约束的参数T In the example implementations provided, you added a type constraint to the generic parameter T , which does not match the function in the protocol.在提供的示例实现中,您向泛型参数T添加了类型约束,它与协议中的 function 不匹配。

There's more than one way you can approach a solution to this problem.有不止一种方法可以解决这个问题。 Keeping in mind that you said all entities will conform to Mockable , the solution that requires the least change to the code you provided is to use protocol composition to enforce that all parameters T conform to both Decodable and Mockable .请记住,您说所有实体都将符合Mockable ,需要对您提供的代码进行最少更改的解决方案是使用协议组合来强制所有参数T符合DecodableMockable

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

In your clients, you would implement that function exactly as written.在您的客户中,您将完全按照所写的方式实现 function。

Now, in your MockClient , you can call T.mock() , and in your real implementations, you can treat T as Decodable as required.现在,在您的MockClient中,您可以调用T.mock() ,并且在您的实际实现中,您可以根据需要将T视为Decodable Of course, this now requires that even your mock arguments conform to Decodable , but I would assume your mock arguments will be fairly lightweight and thus this wouldn't be a problem.当然,现在这要求即使您的模拟 arguments 也符合Decodable ,但我会假设您的模拟 arguments 将相当轻巧,因此这不会成为问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM