2016-06-08 49 views
3

我试图使用flatMap在Swift中构建一个Resource<T>,但不断收到一个奇怪的错误,并且只在我强制转换时才起作用。Swift flatMap和泛型

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轻松转换为结构体,而无需编写大量样板代码。

回答

4

丹尼尔·霍尔的答案是正确的,但是,这样做,你将被迫改变你parser初始化签名接收(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,你可以只返回resource.parser(json: dataJson)

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? 
} 
+0

但不会这也导致改变'struct'的初始值设定项? – Victor

+1

@Victor是的:)我并不是暗示不需要其他更改,只是代码中的错误位于该位置。 –