有人可以帮助解决方案吗,正如我在底部所描述的那样,任何变体都无法通过(或者不是??),但是也许有人知道非常接近的解决方案?
P.S。请查看代码注释中的描述。
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)
}
也许不是正确的方法?
答案 0 :(得分:0)
您要尝试的是通用差异,它仅在数组中本地受支持。
因此,这是您的用法示例的解决方法。但是在此之前,您的示例需要首先修复,因为它目前尚未编译。 ApiFailures
应该是符合Error
的类,而Endpoint1Failure
也应该是一个类。其大小写应重写为static let
。
解决方法是仅使用非通用on
方法,并按如下方式编写调用方:
router.on("/ok") { request in
return Result<Endpoint1Success, Endpoint1Failure>.success(.ok)
.map { $0 }.mapError { $0 }
}
本质上,您在每个return语句之后添加.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
之前进行强制转换。在这种解决方法中,您只是在呼叫方进行操作。
答案 1 :(得分:0)
经过长时间的研究,我发现这很关键: https://github.com/apple/swift/pull/13012 和'广义超类型约束”看起来很必要。 如我所见,已于2019年11月19日接受(或不接受)实施,结果应等待Swift 6 +。