我正在尝试使用flatMap在Swift中构建Resource<T>
,但是一直遇到一个奇怪的错误,只有当我强制执行强制转换时才会有效。
Resource<T>
:
public struct Resource<T> {
let record: CKRecord
let parser: [String: AnyObject] -> T?
}
工作代码:
public func buildResource<T>(resource: Resource<T>) -> T? {
var dataJson: [String: AnyObject] = [:]
dataJson["recordID"] = resource.record.recordID
for name in resource.record.attributeKeys {
dataJson[name] = resource.record[name]
}
return (dataJson as? [String: AnyObject]).flatMap(resource.parser)
}
上面的代码给出了一个警告,表明强制转换总是成功,这是真的。但是当我试图像这样删除演员时:
public func buildResource<T>(resource: Resource<T>) -> T? {
var dataJson: [String: AnyObject] = [:]
dataJson["recordID"] = resource.record.recordID
for name in resource.record.attributeKeys {
dataJson[name] = resource.record[name]
}
return dataJson.flatMap(resource.parser)
}
它出现以下错误:'flatMap' produces '[S.Generator.Element]', not the expected contextual result type 'T'?
。
解析器是struct init
,如此:
struct Example {
let name: String
let id: Int
}
extension Example {
init?(dataJson: [String: AnyObject]) {
guard let name = dataJson["name"] as? String else {
return nil
}
guard let id = dataJson["id"] as? Int else {
return nil
}
self.name = name
self.id = id
return
}
}
任何想法如何解决这个或不同的方法?这里的想法是将任何CKRecord转换为结构,而无需编写大量的样板代码。
答案 0 :(得分:4)
Daniel Hall的回答是正确的,但是,通过这样做,您将被迫更改parser
初始签名以接收(String, AnyObject)
。
最好的选择是使用此签名创建另一个init
并将其解析为json
签名的init
,仍然可以从原始{{1}创建此结构}。
json
修改强>
当您将extension Example {
init?(json: [String: AnyObject]) {
guard let name = json["name"] as? String else {
return nil
}
guard let id = json["id"] as? Int else {
return nil
}
self.name = name
self.id = id
return
}
init (tuple : (String, AnyObject)) {
var json : [String : AnyObject] = [:]
json["name"] = tuple.0
json["id"] = tuple.1
self.init(json: json)!
}
}
创建为dataJson
时,您无需在其上[String : AnyObject]
,只需返回flatMap
答案 1 :(得分:3)
您的解析器功能看起来有错误的签名。整个json字典的类型为[String : AnyObject]
,但使用flatMap()
枚举时该字典中的各个元素的类型为(String, AnyObject)
,而不是[String : AnyObject]
。
尝试更改此内容:
public struct Resource<T> {
let record: CKRecord
let parser: [String: AnyObject] -> T?
}
到此:
public struct Resource<T> {
let record: CKRecord
let parser: (String, AnyObject) -> T?
}