Протокол расширения Encodable (или Codable) не соответствует ему - PullRequest
0 голосов
/ 15 мая 2018

У меня есть 2 протокола, Filters и Parameters, оба из которых расширяются 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» не соответствует протоколу «Encodable»

примечание: не может автоматически синтезировать «Encodable», поскольку «Filters» не соответствует «Encodable»

Filters ясно действительно соответствует Encodable (по крайней мере, мне так кажется). Есть ли способ обойти это?

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Как обсуждено в Протокол не соответствует сам по себе? , протокол не соответствует сам по себе или протокол, от которого он наследует. В вашем случае Filters не не соответствует Encodable.

Возможное решение - сделать struct BankAccountParamters и protocol 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}}
0 голосов
/ 15 мая 2018

Вы не можете иметь ссылку на протокол в структуре, так как компилятор не сможет узнать тип во время кодирования. Здесь сообщается об ошибке 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}}
...