为什么`decode(_:forKey:)`忽略它的第一个参数?

时间:2017-09-16 22:42:57

标签: swift codable

似乎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?

1 个答案:

答案 0 :(得分:1)

decode(...)调用的元类型参数用于专门化泛型参数。 Swift没有像C ++那样手动专门化泛型的语法(例如decode<Int>(forKey: ...)),所以这是一种将泛型参数绑定到具体类型的方法。

传入元类型(而不是依赖于返回类型来提供解析)的好处是表达式的结果是明确的。依赖返回结果可能会导致一些令人惊讶的情况:

protocol DefaultInitializable {
    init()
}

func defaultValue<T : DefaultInitializable>() -> T {
    return T()
}

func foo(_ value: Int) {
    print(value)
}

foo(defaultValue())

结果

Untitled.swift:13:5: error: generic parameter 'T' could not be inferred
foo(defaultValue())
    ^
Untitled.swift:5:6: note: in call to function 'defaultValue'
func defaultValue<T : DefaultInitializable>() -> T {
     ^

使用显式元类型,这不是问题。

至于为什么泛型类型被用于传入的元类型的具体实例 - 通常意外的是,具体的元类型实例具有与其自身不同的静态类型。