下标:使用 String 枚举访问我的字典值
Subscript: access my dictionary values with a String enumeration
我想做类似的事情:使用 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 给我的 Json 解析词典。我很确定我不能改变它的类型。
试试这个:
extension Dictionary where Key: StringLiteralConvertible {
subscript(index: JsonKeys) -> Value {
get {
return self[index.rawValue as! Key]!
}
}
}
请记住,在具有 Key: StringLiteralConvertible
约束的情况下,扩展适用于任何其 Key 符合 StringLiteralConvertible
的词典。 (你知道 String
以外的许多类型都符合 StringLiteralConvertible
。)
要调用下标self[]
,您需要传递一个Key
类型的值。 index.rawValue
是 String
,在扩展名中可能并不总是 Key
。
因此,我展示的扩展适用于某些词典,但会导致其他一些词典的运行时崩溃。
更类型安全的方式:
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)]!
}
}
}
最简单的方法是将字典提升到更多上下文中。本例中的上下文是 "it only has keys from this enum." 在 Swift 中提升类型非常简单。只需将其包装在一个结构中即可。
// 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]
我知道这是一个老问题,但我想我会添加一个更易于扩展、重用和更轻量级的实现
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"
我想做类似的事情:使用 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 给我的 Json 解析词典。我很确定我不能改变它的类型。
试试这个:
extension Dictionary where Key: StringLiteralConvertible {
subscript(index: JsonKeys) -> Value {
get {
return self[index.rawValue as! Key]!
}
}
}
请记住,在具有 Key: StringLiteralConvertible
约束的情况下,扩展适用于任何其 Key 符合 StringLiteralConvertible
的词典。 (你知道 String
以外的许多类型都符合 StringLiteralConvertible
。)
要调用下标self[]
,您需要传递一个Key
类型的值。 index.rawValue
是 String
,在扩展名中可能并不总是 Key
。
因此,我展示的扩展适用于某些词典,但会导致其他一些词典的运行时崩溃。
更类型安全的方式:
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)]!
}
}
}
最简单的方法是将字典提升到更多上下文中。本例中的上下文是 "it only has keys from this enum." 在 Swift 中提升类型非常简单。只需将其包装在一个结构中即可。
// 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]
我知道这是一个老问题,但我想我会添加一个更易于扩展、重用和更轻量级的实现
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"