【问题标题】:Swift: Assign an instance of a generic type to a class variable?Swift:将泛型类型的实例分配给类变量?
【发布时间】:2020-08-20 04:32:01
【问题描述】:

我正在尝试使用这个 https://github.com/bricklife/JSONRPCKit 。它是 Swift 的 JSONRPC 的简单实现。

这是自述文件中的示例。很简单。

// Generating request JSON
let batchFactory = BatchFactory(version: "2.0", idGenerator: NumberIdGenerator())
let request = Subtract(minuend: 42, subtrahend: 23)
let batch = batchFactory.create(request)
batch.requestObject // ["jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1]

// Parsing response JSON
let responseObject: Any = ["jsonrpc": "2.0", "result": 19, "id": 1]
let response = try! batch.responses(from: responseObject)

我想跟踪batch,即使它是在类的函数中创建的。所以另一个功能(当我从我的服务器收到回复时)。可以访问特定的请求/批处理/批处理元素并执行它需要的任何功能。

我无法使用 JSONRPCKit 中的任何类型在我的类中创建变量。

我收到如下编译器错误:

Protocol 'Batch' 只能用作通用约束,因为它具有 Self 或关联的类型要求

对泛型“Batch1”的引用需要 <...>

中的参数

协议类型'Request'的值不能符合'Request';只有结构/枚举/类类型可以符合协议

我尝试以某种方式使用泛型 in 函数来避免我的问题,但这也无济于事。

    func store_b<Batch: JSONRPCKit.Batch>(_ batch: Batch){

更多信息:batchBatch1 类型,如下所示:

public struct Batch1<Request: JSONRPCKit.Request>: Batch {

Batch 是一个协议

public protocol Batch {

是否有一种简单的方法来跟踪我的batch 请求并获得响应/如何正确使用这些泛型

【问题讨论】:

    标签: swift generics


    【解决方案1】:

    分解 create 方法签名和 Batch1 类型

    public func create<Request: JSONRPCKit.Request>(_ request: Request) -> Batch1<Request>
    
    public struct Batch1<Request: JSONRPCKit.Request>: Batch {
        public typealias Responses = Request.Response
        public typealias Results = Result<Request.Response, JSONRPCError>
    }
    

    create 是一个通用函数,它接受一个任何类型的参数。约束&lt;Request: JSONRPCKit.Request&gt; 指定参数的类型必须符合协议JSONRPCKit.Request

    Batch1 是一个泛型结构,需要定义两个内部类型,这两个类型都与一些任意类型相关联。同样,&lt;Request: JSONRPCKit.Request&gt; 指定任意类型必须符合协议JSONRPCKit.Request

    返回类型Batch1&lt;Request&gt; 将这两个泛型联系在一起,表示用于返回的Batch1 结构的类型将匹配request 参数的类型。

    调用create方法时,必须用具体类型填写泛型类型,如示例中

    let batch = batchFactory.create(Subtract(minuend: 42, subtrahend: 23))
    

    现在编译器可以遍历所有定义并为该类型创建具体实现:

    public func create(_ request: Subtract) -> Batch1<Subtract>
    
    public struct Batch1<Subtract>: Batch {
        public typealias Responses = Int
        public typealias Results = Result<Int, JSONRPCError>
    }
    

    这使用了Subtract 定义typealias Response = Int 的事实。请注意,没有什么是通用的了。这些都是具体的类型。尝试存储 Batch1&lt;Subtract&gt; 类型的属性不会有任何问题。


    这就是为什么您不能轻松地将批处理存储在属性中的原因:Swift 不知道要放入什么类型!

    解决这个问题的一种方法是存储一个闭包,这可以包装通用批处理,这样类就不必知道它

    // closure property
    var responseProcessor: ((Any) -> Void)?
    
    func createBatch<R: JSONRPCKit.Request>(request: R, processor: @escaping (R.Response) -> Void) {
        let batch = batchFactory.create(request)
        self.responseProcessor = { responseObject in
            let response = try! batch.responses(from: responseObject)
            processor(response)
        }
    }
    
    // somewhere else when you get the responseObject
    responseProcessor?(responseObject)
    

    此方法采用与泛型类型匹配的特定闭包,并将其包装在不再依赖于泛型的闭包中。这样每个批次都可以共享相同的闭包属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-06
      • 2020-06-08
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多