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

Mat*_*Bak 20 generics ios swift

我有以下 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)
Run Code Online (Sandbox Code Playgroud)

导致错误

Value of protocol type 'Encodable' cannot conform to 'Encodable'; only struct/enum/class types can conform to protocols
Run Code Online (Sandbox Code Playgroud)

怎么修?我想我需要更改 的类型things,但我不知道该怎么做。

附加信息:

如果我更改doStuff为不通用,我只会在该函数中遇到相同的问题

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

vad*_*ian 15

Encodable不能用作带注释的类型。它只能用作通用约束。并且JSONEncoder只能编码具体类型。

功能

func doStuff<T: Encodable>(payload: [String: T]) {
Run Code Online (Sandbox Code Playgroud)

是正确的,但您不能调用该函数,[String: Encodable]因为协议不能符合自身。这正是错误消息所说的。


主要问题是真正的类型things[String:Any]并且Any不能被编码。

你必须序列thingsJSONSerialization或创建一个帮助结构。

  • @vadian 这将是“协议”的全部要点,因此我们不必在运行时关心单个具体类型,而仍然可以调用它声明的函数。如果某个东西是“Encodable”,那么它已经实现了“encode”(它必须实现)。这意味着我不能写 `if let encodable = anyObject as? Encodable { try JSONEncoder().encode(payload) }` 这对我来说很荒谬。 (4认同)
  • 感谢您的解释,但来自其他语言的这种语言功能(限制)对我来说听起来绝对荒谬。`[String: E​​ncodable] 因为协议不能符合自身。` 通过指定 `[String: E​​ncodable]` (至少在 c# 或 typescript 等语言中),我们并不要求接口(或本例中的协议)符合协议本身,我们无法创建接口的实例,因此该值只能是符合协议的struct/class/enum的实例。 (4认同)
  • @vadian 我仍然无法理解它。我正在存储“Encodable”类型的内容,它有一个“encode”函数(它指定了这个合同)。这意味着所有实例都有一个函数“encode”。这意味着我应该能够调用它。 (3认同)
  • 谢谢。我很害怕这个。拥有辅助结构极大地限制了我,因为我只想编码和转储任意数据(符合可编码协议)。 (2认同)
  • “协议”的全部意义不就是声明一个函数以便随时调用它吗?如果它有一个像 `open func encode&lt;T&gt;(_ value: T) throws -&gt; Data where T : Encodable` 这样的函数,我希望它是可调用的。`Swift` 还需要什么?这完全扼杀了一般使用接口的整个想法。接下来,“描述”也需要一个特定的实例吗? (2认同)

Ely*_*Ely 6

您可以将where关键字与Valuetype 结合使用,如下所示:

func doStuff<Value>(payload: Value) where Value : Encodable {
    ...
}
Run Code Online (Sandbox Code Playgroud)