下标:使用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[]
,您需要传递一个Key
types的值。 index.rawValue
是String
,在扩展中可能不总是一个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"