有人可以帮助解决方案,正如我所知道的在底部描述的任何变体都不能通过(或不?),但也许有人知道非常接近的解决方案?
附注:请参阅代码注释中的说明。
import Foundation
public struct HTTPRequest {
// ...
}
public struct HTTPResponse {
// ...
}
public class Router<SuccessResponse, FailureResponse: Swift.Error> {
internal typealias Encoder = (Result<SuccessResponse, FailureResponse>) -> HTTPResponse
internal typealias Responder = (HTTPRequest) -> HTTPResponse
private let encoder: Encoder
internal private(set) var responders: [String: Responder]
internal init(encoder: @escaping Encoder) {
self.encoder = encoder
self.responders = [:]
}
// For me, is not correct! Description further...
public func on(_ path: String, using closure: @escaping (HTTPRequest) -> Result<SuccessResponse, FailureResponse>) {
responders[path] = { request in
let result = closure(request)
return self.encoder(result)
}
}
// It's correct way, in usege, in this variant, you can't use different subtypes of SuccessResponse and FailureResponse, only one concrate type!
// BUT I can't set constraint on SuccessResponse and FailureResponse as this should be a Protocol and in result we have error `... constrained to non-protocol, non-class type ...`
public func on<S: SuccessResponse, F: FailureResponse>(_ path: String, using closure: @escaping (HTTPRequest) -> Result<S, F>) { // Type 'S, ''F' constrained to non-protocol, non-class type 'FailureResponse'
responders[path] = { request in
let result = closure(request)
return self.encoder(result)
}
}
}用法示例,您不能使用任何ApiSuccess或ApiFailure,只能使用受其他泛型约束的具体类型:
protocol ApiSuccess {
// ...
}
protocol ApiFailure {
// ...
}
enum Endpoint1Success: ApiSuccess {
case ok
case empty
}
enum Endpoint1Failure: ApiFailure {
case not
case internalError
}
let router = Router<ApiSuccess, ApiFailure> { result -> HTTPResponse in
switch result {
case .success(let apiSuccess):
// apiSuccess encoded to HTTPResponse
return HTTPResponse()
case .failure(let apiFailure):
// apiFailure encoded to HTTPResponse
return HTTPResponse()
}
}
router.on("/ok") { request -> Result<Endpoint1Success, Endpoint1Failure> in
return .success(.ok)
}
router.on("/not") { request -> Result<Endpoint1Success, Endpoint1Failure> in
return .failure(.not)
}或者可能是不正确的方式?
发布于 2020-01-11 00:50:47
您正在尝试做的是泛型方差,它仅在本地支持用于数组。
下面是你的用法示例的一个变通方法。但在此之前,您的示例需要首先修复,因为它当前不能编译。ApiFailures应该是一个符合Error的类,Endpoint1Failure也应该是一个类。它的案例应该重写为static let%s。
解决方法是仅使用非泛型on方法,并按如下方式编写调用方:
router.on("/ok") { request in
return Result<Endpoint1Success, Endpoint1Failure>.success(.ok)
.map { $0 }.mapError { $0 }
}从本质上讲,您可以在每个返回语句后添加.map { $0 }.mapError { $0 }。这就是从Result<S, F>到Result<ApiSuccess, ApiFailure>的转换方式。如果你不想一直写这段代码,你可以把它提取到一个扩展中:
extension Result where Success : ApiSuccess, Failure : ApiFailure {
func toGeneralApiResult() -> Result<ApiSuccess, ApiFailure> {
map { $0 }.mapError { $0 }
}
}这种强制转换实际上是不可避免的,即使您可以约束您的S和F参数。唯一的区别是你在哪里做这个转换。如果您可以约束S和F,那么您应该在将result传递给encoder之前强制转换它。在这个变通方法中,你只是在调用者这一边做。
发布于 2020-01-11 17:30:41
经过长时间的研究,我发现了这一点:和'Generalized supertype constraints‘看起来是必要的。正如我所看到的,2019年11月19日接受(或不接受)实施,结果应该等待Swift 6+。
https://stackoverflow.com/questions/59677846
复制相似问题