kei*_*ter 9 generics enums dictionary swift swift-extensions
我想延长Dictionary与String键(JSON字典),以便与任何下标enum,有一个RawValue类型的String.最终目标是多个enums可用于下标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] { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
但我无法弄清楚如何实现这一点.我知道我需要扩展Dictionary,但无法弄清楚通用扩展约束或方法扩展约束.
我的第一个想法是尝试向下标方法添加通用约束.不过,我认为下标方法不允许使用泛型.
extension Dictionary {
subscript<T: RawRepresentable>(key: T) -> Value? { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
即使将泛型约束放在下标上,我仍然需要一种方法来嵌套我的泛型约束.或者将字典约束为基于字符串的枚举的键.要把它放在无效的代码中,我想这样做:
extension Dictionary where Key: RawRepresentable where RawValue == String {
subscript(key: Key) -> Value { /* ... */ }
}
// or
extension Dictionary {
subscript<T: RawRepresentable where RawValue == String>(key: T) -> Value { /* ... */ }
}
Run Code Online (Sandbox Code Playgroud)
是否可以扩展Dictionary为接受基于字符串的枚举作为下标?
我对如何实现这样的事情的其他想法包括enum继承和创建enums我想用作下标的特定协议.我知道有些事情无法做到,但认为值得一提的是这个想法.所以,再次,把它放在无效的代码中:
enum JSONKey: String {}
enum NumbersJSONKey: JSONKey {
case one, two, three
}
enum LettersJSONKey: JSONKey {
case a, b, c
}
// or
protocol JSONKeys {}
enum NumbersJSONKey: JSONKey {
case one, two, three
}
enum LettersJSONKey: JSONKey {
case a, b, c
}
// then subscript with
if let one = json[.one] { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
更新:
我已经玩了一些,并且更接近了.下面的扩展编译,但如果我真的尝试使用它,给我一个"下标是模糊的"错误.
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
}
}
Run Code Online (Sandbox Code Playgroud)
@ titaniumdecoy的答案是有效的,除非有人能提出更好的东西,否则它将成为公认的答案.
mlu*_*own 14
借助Swift 4对Generic Subscripts的支持,您现在可以执行以下操作:
extension Dictionary where Key: ExpressibleByStringLiteral {
subscript<Index: RawRepresentable>(index: Index) -> Value? where Index.RawValue == String {
get {
return self[index.rawValue as! Key]
}
set {
self[index.rawValue as! Key] = newValue
}
}
}
Run Code Online (Sandbox Code Playgroud)
这允许您使用任何具有String的Enum作为其RawValue类型:
let value = jsonDict[JSONKey.one]
这将适用于任何String Enum,而不仅仅是 JSONKey
据我所知,你想要任何带有字符串键的Dictionary的扩展,以允许使用带有String的枚举作为其RawValue类型进行下标.如果是这样,以下内容适合您:
enum JSONKey: String {
case one, two, 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]!)
Run Code Online (Sandbox Code Playgroud)
如果你想扩展它以适用于任何使用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)!)
Run Code Online (Sandbox Code Playgroud)