我想用Dictionary键(JSON字典)扩展String,以允许使用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] { /* ... */ }

但是我不知道如何实现这一点。我知道我需要扩展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继承以及为要用作下标的特定enums创建协议(protocol)。我知道其中一些无法完成,但认为值得一提。因此,再次将其放入无效的代码中:
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] { /* ... */ }

更新:

我已经玩了更多,并且离得更近了。下面的扩展名可以编译,但是如果我实际尝试使用它,则会出现“下标不明确”的错误。
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的答案有效,因此除非有人能提出更好的建议,否则它将被接受。

最佳答案

据我了解,您希望对任何具有String键的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]!)

如果要将其扩展为适用于String为RawValue类型的任何枚举,则需要泛型。由于Swift不支持通用下标(请参见SR-115),因此需要get/set方法或属性:
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)!)

关于swift - Swift中带有基于字符串的枚举的下标字典,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38774772/

10-13 03:24