简体   繁体   English

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

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

I have the following Swift code我有以下 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)

results in the error导致错误

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

How to fix?怎么修? I guess I need to change the type of things , but I don't know what to.我想我需要改变things的类型,但我不知道该怎么做。

Additional info:附加信息:

If I change doStuff to not be generic, I simply get the same problem in that function如果我将doStuff更改为不是通用的,我只会在 function 中遇到同样的问题

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

Encodable cannot be used as an annotated type. Encodable不能用作带注释的类型。 It can be only used as a generic constraint.它只能用作通用约束。 And JSONEncoder can encode only concrete types.JSONEncoder只能编码具体类型。

The function function

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

is correct but you cannot call the function with [String: Encodable] because a protocol cannot conform to itself.是正确的,但是您不能使用[String: Encodable]调用 function,因为协议不能符合自身。 That's exactly what the error message says.这正是错误消息所说的。


The main problem is that the real type of things is [String:Any] and Any cannot be encoded.主要问题是things的真实类型是[String:Any]并且Any无法编码。

You have to serialize things with JSONSerialization or create a helper struct.您必须使用JSONSerialization序列化things或创建辅助结构。

You're trying to conform T to Encodable which is not possible if T == Encodable .您正在尝试使T符合Encodable ,如果T == Encodable ,这是不可能的。 A protocol does not conform to itself.协议不符合自身。

Instead you can try:相反,您可以尝试:

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

What you are trying to do is possible with protocol extensions:您可以通过协议扩展来尝试做的事情:

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)
        }
    }
}

Every type that could be in your Dictionary will need to conform to our JsonEncoding protocol. Dictionary中可能包含的每种类型都需要符合我们的JsonEncoding协议。 You used a String and an Int , so here are extensions that add conformance for those two types:您使用了StringInt ,因此这里有为这两种类型添加一致性的扩展:

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

And here is your code doing what you wanted it to do:这是你的代码做你想做的事:

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)

You didn't ask about decoding, so I didn't address it here.你没有问解码,所以我没有在这里解决。 You will either have to have knowledge of what type is associated with what key, or you will have to create an order in which you try to decode values (Should a 1 be turned into an Int or a Double ...).您要么必须知道什么类型与什么键相关联,要么必须创建一个尝试解码值的顺序(应该将1转换为IntDouble ...)。

I answered your question without questioning your motives, but there is likely a better, more "Swifty" solution for what you are trying to do...我在没有质疑您的动机的情况下回答了您的问题,但是对于您正在尝试做的事情,可能有一个更好、更“迅速”的解决方案......

You can use the where keyword combined with Value type, like this:您可以将where关键字与Value类型结合使用,如下所示:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 协议类型“Any”的值不能符合“Equatable”; 只有结构/枚举/类类型可以符合协议 - Value of protocol type 'Any' cannot conform to 'Equatable'; only struct/enum/class types can conform to protocols swift 将字典转换为 jsonString 错误:协议类型 'Any' 不能符合 'Encodable' 因为只有具体类型才能符合协议 - swift Convert dictionary to jsonString error : Protocol type 'Any' cannot conform to 'Encodable' because only concrete types can conform to protocols 类型 &#39;()&#39; 不能符合 &#39;View&#39;; 只有 struct/enum/class 类型才能符合协议; 使用 SwiftUI 调用函数 - Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols; calling functions with SwiftUI navigationBarItems“类型[视图]不能符合'视图'; 只有结构/枚举/类类型可以符合协议” - navigationBarItems “Type [view] cannot conform to 'View'; only struct/enum/class types can conform to protocols” 类型 '()' 不能符合 'View'; 只有结构/枚举/类类型可以符合协议 - Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols Swift 错误:“类型 &#39;()&#39; 不能符合 &#39;View&#39;;只有 struct/enum/class 类型可以符合协议”调用函数写入文本时 - Swift error: "Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols" when calling function to write text 类型不符合“可编码”协议 - Type does not conform to protocol 'Encodable' 我收到错误“类型'(UITextRange)-&gt;字符串?' 不能符合“BinaryInteger”; 只有结构/枚举/类类型可以符合协议” - I got error “Type '(UITextRange) -> String?' cannot conform to 'BinaryInteger'; only struct/enum/class types can conform to protocol” 协议类型不能符合协议,因为只有具体类型才能符合协议 - Protocol type cannot conform to protocol because only concrete types can conform to protocols 类型'X'不符合协议'Encodable' - Type 'X' does not conform to protocol 'Encodable'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM