首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >约束按泛型泛型

约束按泛型泛型
EN

Stack Overflow用户
提问于 2020-01-10 16:23:26
回答 2查看 80关注 0票数 2

有人可以帮助解决方案,正如我所知道的在底部描述的任何变体都不能通过(或不?),但也许有人知道非常接近的解决方案?

附注:请参阅代码注释中的说明。

代码语言:javascript
复制
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,只能使用受其他泛型约束的具体类型:

代码语言:javascript
复制
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)
}

或者可能是不正确的方式?

EN

回答 2

Stack Overflow用户

发布于 2020-01-11 00:50:47

您正在尝试做的是泛型方差,它仅在本地支持用于数组。

下面是你的用法示例的一个变通方法。但在此之前,您的示例需要首先修复,因为它当前不能编译。ApiFailures应该是一个符合Error的类,Endpoint1Failure也应该是一个类。它的案例应该重写为static let%s。

解决方法是仅使用非泛型on方法,并按如下方式编写调用方:

代码语言:javascript
复制
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>的转换方式。如果你不想一直写这段代码,你可以把它提取到一个扩展中:

代码语言:javascript
复制
extension Result where Success : ApiSuccess, Failure : ApiFailure {
    func toGeneralApiResult() -> Result<ApiSuccess, ApiFailure> {
        map { $0 }.mapError { $0 }
    }
}

这种强制转换实际上是不可避免的,即使您可以约束您的SF参数。唯一的区别是你在哪里做这个转换。如果您可以约束SF,那么您应该在将result传递给encoder之前强制转换它。在这个变通方法中,你只是在调用者这一边做。

票数 0
EN

Stack Overflow用户

发布于 2020-01-11 17:30:41

经过长时间的研究,我发现了这一点:和'Generalized supertype constraints‘看起来是必要的。正如我所看到的,2019年11月19日接受(或不接受)实施,结果应该等待Swift 6+。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59677846

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档