Swift flatMap 和泛型
Swift flatMap and generics
我正在尝试使用 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 转换为结构,而无需编写大量样板代码。
您的解析器函数的签名似乎有误。整个 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?
}
Daniel Hall 的回答是正确的,但是,通过这样做,您将被迫更改 parser
init 签名以接收 (String, AnyObject)
。
最好的选择是使用此签名创建另一个 init
并将其解析为您的 json
签名的 init
,仍然能够从原始 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
,您只需 return resource.parser(json: dataJson)
我正在尝试使用 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 转换为结构,而无需编写大量样板代码。
您的解析器函数的签名似乎有误。整个 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?
}
Daniel Hall 的回答是正确的,但是,通过这样做,您将被迫更改 parser
init 签名以接收 (String, AnyObject)
。
最好的选择是使用此签名创建另一个 init
并将其解析为您的 json
签名的 init
,仍然能够从原始 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
,您只需 return resource.parser(json: dataJson)