下标:使用string枚举访问我的字典值

我想要做这样的事情:用string枚举访问我的字典值。 我试图超载字典的下标,但没有成功。

访问字典:

let district = address[JsonKeys.district] 

JsonKeys在哪里:

 enum JsonKeys: String { case key1 case key2 case key... } 

我的下标过载如下:

 extension Dictionary where Key: StringLiteralConvertible, Value: AnyObject { subscript(index: FOJsonKeys) -> AnyObject { get { return self[ index.rawValue] as! AnyObject } } } 

我收到以下消息:

 **Cannot subscript a value of type 'Dictionary<Key, Value>' with an index of type 'String'** 

我错在哪里?

PS:不想这样做(这将纠正错误,但代码是不可读的这种方式):

 let district = address[JsonKeys.district.rawValue] 

字典是由AlamoFire给我的Jsonparsing字典。 我很确定我不能改变它的types。

最简单的方法是将字典提升到更多的上下文中。 在这种情况下的上下文是“它只有从这个枚举键”。 在Swift中提升types非常简单。 把它包装在一个结构中。

 // This could be a nested type inside JSONObject if you wanted. enum JSONKeys: String { case district } // Here's my JSONObject. It's much more type-safe than the dictionary, // and it's trivial to add methods to it. struct JSONObject { let json: [String: AnyObject] init(_ json: [String: AnyObject]) { self.json = json } // You of course could make this generic if you wanted so that it // didn't have to be exactly JSONKeys. And of course you could add // a setter. subscript(key: JSONKeys) -> AnyObject? { return json[key.rawValue] } } let address: [String: AnyObject] = ["district": "Bob"] // Now it's easy to lift our dictionary into a "JSONObject" let json = JSONObject(address) // And you don't even need to include the type. Just the key. let district = json[.district] 

尝试这个:

 extension Dictionary where Key: StringLiteralConvertible { subscript(index: JsonKeys) -> Value { get { return self[index.rawValue as! Key]! } } } 

请记住,通过使用Key: StringLiteralConvertible作为约束,该扩展适用于其密钥符合StringLiteralConvertible任何字典。 (你知道String以外的许多types符合StringLiteralConvertible 。)

要调用下标self[] ,您需要传递一个Keytypes的值。 index.rawValueString ,在扩展中可能不总是一个Key

所以,我所展示的扩展将适用于一些字典,会导致一些其他字典的运行时崩溃。


多一点types安全的方法:

 protocol MyJsonKeysConvertible { init(jsonKeys: JsonKeys) } extension String: MyJsonKeysConvertible { init(jsonKeys: JsonKeys) {self = jsonKeys.rawValue} } extension Dictionary where Key: MyJsonKeysConvertible { subscript(index: JsonKeys) -> Value { get { return self[Key(jsonKeys: index)]! } } } 

我知道这是一个老问题,但我想我会添加一个更容易扩展,重用和更轻量级的实现

 public protocol UsesRawValue { var rawValue: String { get } } extension JsonKeys: UsesRawValue {} extension Dictionary where Key: ExpressibleByStringLiteral { public subscript(key: UsesRawValue) -> Value? { get { return self[key.rawValue as! Key] } set { self[key.rawValue as! Key] = newValue } } } 

基于这个博客文章

这种方法只需要我们扩展字典一次,而不是每个枚举。 相反,每个枚举需要符合UsesRawValue 。 现在我们可以像这样使用它。

 ajson[JsonKeys.key1] ajson[JsonKeys.key1] = "name"