【发布时间】:2017-09-16 22:42:56
【问题描述】:
似乎decode(_forKey:) 忽略了它的第一个参数,而是依赖泛型参数来决定要解码的类型。如果是这样,第一个参数是干什么用的?
class Cat: Codable {
func speak() -> String { return "Meow" }
}
class Lion: Cat {
override func speak() -> String { return "Roar!" }
}
class Person: Codable {
let firstPet: Cat
let secondPet: Cat
init(firstPet: Cat, secondPet: Cat) {
self.firstPet = firstPet
self.secondPet = secondPet
}
enum CodingKeys: CodingKey { case firstPet, secondPet }
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.firstPet = try container.decode(Lion.self, forKey: .firstPet)
let typeOfCat: Cat.Type = Lion.self
self.secondPet = try container.decode(typeOfCat, forKey: .secondPet)
}
}
let before = Person(firstPet: Lion(), secondPet: Lion())
let after = try! JSONDecoder().decode(Person.self, from: JSONEncoder().encode(before))
after.firstPet.speak() //"Roar!"
after.secondPet.speak() //"Meow" ...really?
【问题讨论】:
-
第一个参数用于将泛型参数特化为调用。在超类元类型的变量中传递子类元类型的实例并传入它有点奇怪——你需要在这里做一些具体的事情来阻止你直接传入
Lion.self吗? -
但是泛型参数可以从调用者对返回值所做的事情中推断出来,不是吗? (是的,当然在这个例子中我可以传递
Lion.self,但我真正想做的是解码在运行时确定的各种子类。) -
不,并非总是如此——在某些情况下,依赖返回类型会导致难以追踪的模糊性;传递元类型参数是防止这种歧义的唯一保证方法。代码可以使用传入的具体元类型而不是通用参数,但这是一个非常独特的用例。不过,您应该可以在运行时打开类型并使用正确的静态类型调用 decode。
-
有趣——我想你的第一条评论实际上就是答案。想写出来吗? (而且,我无法切换,因为在编译时甚至不知道 possible 类型——我不得不对
superDecoder()进行一些可疑的使用,所以我可以直接调用init(from:)正确的类型。) -
已发表,谢谢!顺便说一句,如果您认为这是一个错误,请将其提交到 bugs.swift.org。