簡體   English   中英

協議類型“Encodable”的值不能符合“Encodable”; 只有結構/枚舉/類類型可以符合協議

[英]Value of protocol type 'Encodable' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols

我有以下 Swift 代碼

func doStuff<T: Encodable>(payload: [String: T]) {
    let jsonData = try! JSONEncoder().encode(payload)
    // Write to file
}

var things: [String: Encodable] = [
    "Hello": "World!",
    "answer": 42,
]

doStuff(payload: things)

導致錯誤

Value of protocol type 'Encodable' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols

怎么修? 我想我需要改變things的類型,但我不知道該怎么做。

附加信息:

如果我將doStuff更改為不是通用的,我只會在 function 中遇到同樣的問題

func doStuff(payload: [String: Encodable]) {
    let jsonData = try! JSONEncoder().encode(payload) // Problem is now here
    // Write to file
}

Encodable不能用作帶注釋的類型。 它只能用作通用約束。 JSONEncoder只能編碼具體類型。

function

func doStuff<T: Encodable>(payload: [String: T]) {

是正確的,但是您不能使用[String: Encodable]調用 function,因為協議不能符合自身。 這正是錯誤消息所說的。


主要問題是things的真實類型是[String:Any]並且Any無法編碼。

您必須使用JSONSerialization序列化things或創建輔助結構。

您正在嘗試使T符合Encodable ,如果T == Encodable ,這是不可能的。 協議不符合自身。

相反,您可以嘗試:

func doStuff<T: Hashable>(with items: [T: Encodable]) {
    ...
}

您可以通過協議擴展來嘗試做的事情:

protocol JsonEncoding where Self: Encodable { }

extension JsonEncoding {
    func encode(using encoder: JSONEncoder) throws -> Data {
        try encoder.encode(self)
    }
}

extension Dictionary where Value == JsonEncoding {
    func encode(using encoder: JSONEncoder) throws -> [Key: String] {
        try compactMapValues {
            try String(data: $0.encode(using: encoder), encoding: .utf8)
        }
    }
}

Dictionary中可能包含的每種類型都需要符合我們的JsonEncoding協議。 您使用了StringInt ,因此這里有為這兩種類型添加一致性的擴展:

extension String: JsonEncoding { }
extension Int: JsonEncoding { }

這是你的代碼做你想做的事:

func doStuff(payload: [String: JsonEncoding]) {
    let encoder = JSONEncoder()
    do {
        let encodedValues = try payload.encode(using: encoder)
        let jsonData = try encoder.encode(encodedValues)
        
        // Write to file
    } catch {
        print(error)
    }
}

var things: [String: JsonEncoding] = [
    "Hello": "World!",
    "answer": 42
]

doStuff(payload: things)

你沒有問解碼,所以我沒有在這里解決。 您要么必須知道什么類型與什么鍵相關聯,要么必須創建一個嘗試解碼值的順序(應該將1轉換為IntDouble ...)。

我在沒有質疑您的動機的情況下回答了您的問題,但是對於您正在嘗試做的事情,可能有一個更好、更“迅速”的解決方案......

您可以將where關鍵字與Value類型結合使用,如下所示:

func doStuff<Value>(payload: Value) where Value : Encodable {
    ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM