扩展可编码(或可编码)的协议不符合它



我有 2 个协议,FiltersParameters,两者都扩展Encodable

protocol Filters: Encodable {
var page: Int { get }
}
protocol Parameters: Encodable {
var type: String { get }
var filters: Filters { get }
}

我创建了符合这些协议的结构,因此...

struct BankAccountFilters: Filters {
var page: Int
var isWithdrawal: Bool
}
struct BankAccountParamters: Parameters {
let type: String = "Bank"
var filters: Filters
}
let baf = BankAccountFilters(page: 1, isWithdrawal: true)
let bap = BankAccountParamters(filters: baf)

失败是因为...

错误:类型"BankAccountParamters"不符合协议"可编码">

注意:无法自动合成"可编码",因为"过滤器"不符合"可编码">

Filters显然符合Encodable(至少在我看来是这样(。有没有办法解决这个问题?

正如协议不符合自身?中所讨论的,协议不符合自身,或者 它继承自的协议。在您的情况下,Filters不符合Encodable

一个可能的解决方案是使struct BankAccountParamtersprotocol Parameters通用:

protocol Filters: Encodable {
var page: Int { get }
}
protocol Parameters: Encodable {
associatedtype T: Filters
var type: String { get }
var filters: T { get }
}
struct BankAccountFilters: Filters {
var page: Int
var isWithdrawal: Bool
}
struct BankAccountParamters<T: Filters>: Parameters {
let type: String = "Bank"
var filters: T
}

现在var filters有类型T,它符合Filters,因此符合Encodable

这将编译并生成预期的结果:

let baf = BankAccountFilters(page: 1, isWithdrawal: true)
let bap = BankAccountParamters(filters: baf)
let data = try! JSONEncoder().encode(bap)
print(String(data: data, encoding: .utf8)!)
// {"type":"Bank","filters":{"isWithdrawal":true,"page":1}}

结构中不能有协议引用,因为编译器在编码时将无法知道类型。这是报告的 SR-5853 错误。

您可以做的是为协议创建类型纠删,并使用纠删来代替协议。

像这样:

更新:正如@MartinR回答的那样,这里不需要类型擦除。

protocol Filters: Encodable {
var page: Int { get }
}
protocol Parameters: Encodable {
associatedtype T: Filters
var type: String { get }
var filters: T { get }
}
struct BankAccountFilters: Filters {
var page: Int
var isWithdrawal: Bool
}
struct BankAccountParamters<T: Filters>: Parameters {
let type: String = "Bank"
var filters: T
}
let baf = BankAccountFilters(page: 1, isWithdrawal: true)
let bap = BankAccountParamters(filters: baf)
let encoder = JSONEncoder()
let data = try! encoder.encode(bap)
print(String(data: data, encoding: .utf8)!)

在这里,您将获得输出:

{"type":"Bank","filters":{"isWithdrawal":true,"page":1}}

要在不使用泛型的情况下获得所需的内容,由于在代码中使用泛型会带来多个问题,您可以为结构BankAccountParameters提供自己的encode方法实现。

extension BankAccountParamters {
enum CodingKeys: String, CodingKey {
case type, filters
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(type, forKey: .type)
if let bankAccountFilters = filters as? BankAccountFilters {
try container.encode(bankAccountFilters, forKey: .filters)
} else {
assertionFailure("Type conforming to Filters is not encoded properly")
}
}

这样,您的类型就不必具有泛型约束。但另一方面,您必须确保将来符合Filters的所有类型都正确编码,这就是 else 块上的assertionFailure可能会有所帮助的地方。

同样,如果要解码BankAccountParameters结构,则必须提供init(from: Decoder)的自定义实现。

相关内容

  • 没有找到相关文章

最新更新