我想用String键(
JSON字典)扩展Dictionary,以允许使用任何具有RawValue类型String的枚举进行下标.最终目标是多个枚举,可用于下标JSON词典.
enum JSONKey: String { case one,two,three } enum OtherJSONKey: String { case a,b,c } if let one = jsonDictionary[.one] { /* ... */ } if let b = jsonDictionary[.b] { /* ... */ }
但我无法弄清楚如何实现这一点.我知道我需要扩展Dictionary,但无法弄清楚泛型扩展约束或方法扩展约束.
我的第一个想法是尝试向下标方法添加通用约束.不过,我认为下标方法不允许使用泛型.
extension Dictionary { subscript<T: RawRepresentable>(key: T) -> Value? { /* ... */ } }
即使将泛型约束放在下标上,我仍然需要一种方法来嵌套我的泛型约束.或者将字典约束为基于字符串的枚举的键.要把它放在无效的代码中,我想这样做:
extension Dictionary where Key: RawRepresentable where RawValue == String { subscript(key: Key) -> Value { /* ... */ } } // or extension Dictionary { subscript<T: RawRepresentable where RawValue == String>(key: T) -> Value { /* ... */ } }
是否将Dictionary扩展为接受基于字符串的枚举作为下标实际可行?
我对如何实现这样的事情的其他想法包括枚举继承和为我想用作下标的特定枚举创建协议.我知道有些事情无法做到,但认为值得一提的是这个想法.所以,再次,把它放在无效的代码中:
enum JSONKey: String {} enum NumbersJSONKey: JSONKey { case one,three } enum LettersJSONKey: JSONKey { case a,c } // or protocol JSONKeys {} enum NumbersJSONKey: JSONKey { case one,c } // then subscript with if let one = json[.one] { /* ... */ }
更新:
我已经玩了一些,并且更接近了.下面的扩展编译,但如果我真的尝试使用它,给我一个“下标是模糊的”错误.
extension Collection where Iterator.Element == (key: String,value: AnyObject) { // Compiles but can't be used because of ambiguous subscript. subscript(key: CustomStringConvertible) -> AnyObject? { guard let i = index(where: { $0.key == key.description }) else { return nil } return self[i].value } }
@ titaniumdecoy的答案是有效的,除非有人能提出更好的东西,否则它将成为公认的答案.
据我所知,你想要任何带有字符串键的Dictionary的扩展,以允许使用带有String的枚举作为其RawValue类型进行下标.如果是这样,以下内容适合您:
enum JSONKey: String { case one,three } class JSONObject { } extension Dictionary where Key: StringLiteralConvertible { subscript(jsonKey: JSONKey) -> Value? { get { return self[jsonKey.rawValue as! Key] } set { self[jsonKey.rawValue as! Key] = newValue } } } var jsonDict: [String: AnyObject] = [:] jsonDict[JSONKey.one] = JSONObject() jsonDict["two"] = JSONObject() print(jsonDict["one"]!) print(jsonDict[JSONKey.two]!)
如果你想扩展它以适用于任何使用String作为RawValue类型的枚举,你需要泛型.由于Swift不支持通用下标(参见SR-115),因此需要获取/设置方法或属性:
enum AnotherEnum: String { case anotherCase } extension Dictionary where Key: StringLiteralConvertible { func getValue<T: RawRepresentable where T.RawValue == String>(forKey key: T) -> Value? { return self[key.rawValue as! Key] } mutating func setValue<T: RawRepresentable where T.RawValue == String>(value: Value,forKey key: T) { self[key.rawValue as! Key] = value } } jsonDict.setValue(JSONObject(),forKey: AnotherEnum.anotherCase) print(jsonDict.getValue(forKey: AnotherEnum.anotherCase)!)