2016-06-08 77 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是的:)我並不是暗示不需要其他更改,只是代碼中的錯誤位於該位置。 –