【发布时间】:2019-03-02 21:12:42
【问题描述】:
我正在尝试编写一个通用函数来解析几种不同的数据类型。
原来这个方法只适用于 Codable 类型,所以它的泛型类型被<T: Codable> 约束,一切都很好。但是现在,如果返回类型是 Codable,我正在尝试将其扩展为 check,并根据该检查相应地解析数据
func parse<T>(from data: Data) throws -> T? {
switch T.self {
case is Codable:
// convince the compiler that T is Codable
return try? JSONDecoder().decode(T.self, from: data)
case is [String: Any].Type:
return try JSONSerialization.jsonObject(with: data, options: []) as? T
default:
return nil
}
}
所以你可以看到类型检查工作正常,但我坚持让JSONDecoder().decode(:) 接受T 作为Codable 类型,一旦我检查它是。上面的代码没有编译,有错误
Cannot convert value of type 'T' (generic parameter of instance method 'parse(from:)') to expected argument type 'T' (generic parameter of instance method 'decode(_:from:)')
和
In argument type 'T.Type', 'T' does not conform to expected type 'Decodable'
我尝试了许多强制转换技术,例如let decodableT: <T & Decodable> = T.self 等,但都失败了——通常基于Decodable 是协议而T 是具体类型这一事实。
是否可以(有条件地)将协议一致性重新引入到像这样的已擦除类型?我很感激你有任何想法,无论是解决这种方法还是类似的通用解析方法,在这里可能会更成功。
编辑:一个并发症
@vadian 很有帮助地建议创建两个具有不同类型约束的 parse(:) 方法,以使用一个签名来处理所有情况。在许多情况下,这是一个很好的解决方案,如果您以后遇到这个问题,它可能会很好地解决您的难题。
不幸的是,这仅在调用 parse(:) 时已知类型才有效——在我的应用程序中,此方法由另一个泛型方法调用,这意味着该类型已被删除并且编译器可以' t 选择一个正确约束的 parse(:) 实现。
所以,为了澄清这个问题的症结所在:是否可以有条件地/可选地将类型信息(例如协议一致性)back 添加到已擦除的类型中?换句话说,一旦一个类型变成了<T>,有没有办法将它转换为<T: Decodable>?
【问题讨论】:
标签: swift generics casting codable type-erasure