Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 使用枚举';s默认值作为字典键,而不显式强制转换为字符串_Swift_Dictionary_Enums_Key - Fatal编程技术网

Swift 使用枚举';s默认值作为字典键,而不显式强制转换为字符串

Swift 使用枚举';s默认值作为字典键,而不显式强制转换为字符串,swift,dictionary,enums,key,Swift,Dictionary,Enums,Key,如果我像这样声明一个enum: enum Keys { case key_one case key_two } var myDict = [String : String]() myDict[Keys.key_one.rawValue] = "firstKey" myDict[Keys.key_one] = "firstKey" myDict[Keys.key_one] 我可以打印它,它将自动转换为字符串: print(Keys.key_one) // prints "k

如果我像这样声明一个
enum

enum Keys {
    case key_one
    case key_two
}
var myDict = [String : String]()

myDict[Keys.key_one.rawValue] = "firstKey"
myDict[Keys.key_one] = "firstKey"
myDict[Keys.key_one]
我可以打印它,它将自动转换为
字符串

print(Keys.key_one) // prints "key_one"
如果我再制作一个字典,将
字符串
映射到任何东西(但为了简单起见,让我们再次选择
字符串
),我认为它应该能够使用
键添加一个键。key\u one
作为键,对吗?错

var myDict = [String : String]()

/// error: cannot subscript a value of type '[String : String]' with an index
/// of type 'Keys'
myDict[Keys.key_one] = "firstKey"
如果我显式地将
键。key_one
转换为
字符串
,我就可以这样做,不过如下所示:

myDict[String(Keys.key_one)] = "firstKey"
print(myDict) // ["key_one": "firstKey"]
因此,我想这样做,而不必每次都用
String()
包装我的
enum
。 我尝试了一些方法,使用
where
关键字和
键对
字典进行
扩展
,并尝试实现新的
下标
函数,但我无法让它工作。有什么诀窍

解决方案更新
我找到了我的解决方案()。

键是字符串有多重要?如果这不重要,我建议做如下事情:

enum Keys {
    case key_one
    case key_two
}

var myDict = [Keys : String]()

myDict[Keys.key_one] = "firstKey"
print(myDict) // [Keys.key_one: "firstKey"]
或者你可以:

enum Keys: String {
    case key_one
    case key_two
}
然后像这样使用它:

enum Keys {
    case key_one
    case key_two
}
var myDict = [String : String]()

myDict[Keys.key_one.rawValue] = "firstKey"
myDict[Keys.key_one] = "firstKey"
myDict[Keys.key_one]

更新

如果你真的想让它工作,你可以做如下。但强制拆开包装会带来一些风险

extension Dictionary where Key: StringLiteralConvertible {
    subscript (key: Keys) -> Value? {
        get {
            return self[key.rawValue as! Key]
        }
        set {
            self[key.rawValue as! Key] = newValue
        }
    }
}
然后你像这样使用它:

enum Keys {
    case key_one
    case key_two
}
var myDict = [String : String]()

myDict[Keys.key_one.rawValue] = "firstKey"
myDict[Keys.key_one] = "firstKey"
myDict[Keys.key_one]
Swift 4.2的更新和改进 我专门更改了这3个词典的类型,以显示键入词典的常用方式(
[AnyHashable:Any]
[String:Any]
、和
[String:String]
),并表明这适用于每种类型

需要注意的是,如果在字典的键为
AnyHashable
时使用
updateValue
而不是赋值运算符,则需要使用
.stringValue
指定键的
字符串
值。否则,要存储的键的确切类型将不会显式地是
字符串
,并且如果您尝试(例如)通过将
nil
分配给该键来删除键下的值,它将在以后出错。对于键被专门键入为
String
的字典,则
updateValue
函数将有一个编译时错误,表示键需要是
字符串,因此不能这样搞砸

Swift 2.3 我找到了我想要的扩展解决方案

extension Dictionary {
    
    subscript(key: Keys) -> Value? {
        get {
            return self[String(key) as! Key]
        }
        set(value) {
            guard
                let value = value else {
                    self.removeValueForKey(String(key) as! Key)
                    return
            }

            self.updateValue(value, forKey: String(key) as! Key)
        }
    }

}

enum Keys {
    case key_one
    case key_two
}

var myStringDict = [String : String]()
/// Adding the first key value through the String() way on purpose
myStringDict.updateValue("firstValue", forKey: String(Keys.key_one))
// myStringDict: ["key_one": "firstValue"]
// myStringDict[Keys.key_one]!: firstValue

myStringDict[Keys.key_two] = "secondValue"
// myStringDict: ["key_one": "firstValue", "key_two": "secondValue"]

myStringDict[Keys.key_one] = nil
// myStringDict: ["key_two": "secondValue"]
注意,声明的dictionary键类型是
String
,但我只能使用
键。key\u one
和dictionary扩展中的下标负责其余部分

我可能可以在
周围设置一些更好的防护转换为
,但我不确定是否需要它,因为我知道我的枚举总是可以通过
字符串()转换为有效的

答案的改进 更好的是,因为我将此用于API密钥,所以我创建了一个名为
APIKeys
的空白协议,每个模型将实现它们自己的
Keys
enum,它符合
APIKeys
协议。字典的下标被更新为接受
APIKeys
作为
Key

extension Dictionary {
    
    subscript(key: APIKeys) -> Value? {
        get {
            return self[String(key) as! Key]
        }
        set(value) {
            guard
                let value = value else {
                    self.removeValueForKey(String(key) as! Key)
                    return
            }

            self.updateValue(value, forKey: String(key) as! Key)
        }
    }

}

protocol APIKeys {}

enum Keys: APIKeys {
    case key_one
    case key_two
}

enum Model1Keys: APIKeys {
    case model_1_key_one
    case model_1_key_two
}

enum Model2Keys: APIKeys {
    case model_2_key_one
    case model_2_key_two
}

var myStringDict = [String : String]()
var model1StringDict = [String : String]()
var model2StringDict = [String : String]()

myStringDict.updateValue("firstValue", forKey: String(Keys.key_one))    // myStringDict: ["key_one": "firstValue"]
myStringDict[Keys.key_two] = "secondValue"                              // myStringDict: ["key_one": "firstValue", "key_two": "secondValue"]
myStringDict[Keys.key_one] = nil                                        // myStringDict: ["key_two": "secondValue"]

model1StringDict.updateValue("firstValue", forKey: String(Model1Keys.model_1_key_one))  // model1StringDict: ["model_1_key_one": "firstValue"]
model1StringDict[Model1Keys.model_1_key_two] = "secondValue"                            // model1StringDict: ["model_1_key_one": "firstValue", "model_1_key_two": "secondValue"]
model1StringDict[Model1Keys.model_1_key_one] = nil                                      // model1StringDict: ["model_1_key_two": "secondValue"]

model2StringDict.updateValue("firstValue", forKey: String(Model2Keys.model_2_key_one))  // model2StringDict: ["model_2_key_one": "firstValue"]
model2StringDict[Model2Keys.model_2_key_two] = "secondValue"                            // model2StringDict: ["model_2_key_one": "firstValue", "model_2_key_two": "secondValue"]
model2StringDict[Model2Keys.model_2_key_one] = nil                                      // model2StringDict: ["model_2_key_two": "secondValue"]

我的钥匙是字符串是非常重要的。只是因为它们不是我的字典。这是一本现存的字典。应该有办法对字典进行扩展。这是我真正想要的解决方案。谢谢,但那不行。我不妨只做
String(key.key\u one)
。到处添加
rawValue
并不比到处添加
String()
好。@TimFuqua最坏的情况是,您可以使用
static let key\u one:String
替换
case key\u one
。我知道有些人会这样做。@TimFuqua枚举和字符串是两种不同的类型,不能强制使用,您应该期望一些样板代码能够互换使用它们。我目前正在将一组静态let字符串放入一个结构中。但是应该有一种方法来扩展字典,并将样板代码放到这个空间中。哇,算了吧。没有看到你自己的答案。