在enum中不使用rawValue访问字符串值

时间:2023-01-26 13:56:14

I would like to replace my global string constants with a nested enum for the keys I'm using to access columns in a database.

我想将全局字符串常量替换为用于访问数据库中的列的键的嵌套枚举。

The structure is as follows:

结构如下:

enum DatabaseKeys {

    enum User: String {
        case Table = "User"
        case Username = "username"
        ...
    }

    ...

}

Each table in the database is an inner enum, with the name of the table being the enum's title. The first case in each enum will be the name of the table, and the following cases are the columns in its table.

数据库中的每个表都是一个内部枚举,表的名称是枚举的标题。每个enum中的第一个案例将是表的名称,下面的案例是表中的列。

To use this, it's pretty simple:

使用这个,非常简单:

myUser[DatabaseKeys.User.Username.rawValue] = "Johnny"

But I will be using these enums a lot. Having to append .rawValue to every instance will be a pain, and it's not as readable as I'd like it to be. How can I access the String value without having to use rawValue? It'd be great if I can do this:

但是我将会经常使用这些枚举。必须将。rawvalue添加到每个实例将会很痛苦,而且它不像我希望的那样可读。如何在不使用rawValue的情况下访问字符串值?如果我能做到:

myUser[DatabaseKeys.User.Username] = "Johnny"

Note that I'm using Swift 2. If there's an even better way to accomplish this I'd love to hear it!

注意,我使用的是Swift 2。如果有更好的方法来实现这个目标,我很乐意听到!

4 个解决方案

#1


16  

While I didn't find a way to do this using the desired syntax with enums, this is possible using structs.

虽然我没有找到一种方法来使用所需的枚举语法来实现这一点,但这是可以使用struct的。

struct DatabaseKeys {

    struct User {
        static let identifier = "User"
        static let Username = "username"
    }

}

To use:

使用方法:

myUser[DatabaseKeys.User.Username] = "Johnny"

Apple uses structs like this for storyboard and row type identifiers in the WatchKit templates.

Apple在WatchKit模板中对故事板和行类型标识符使用类似的结构。

#2


7  

You can use CustomStringConvertible protocol for this.

您可以为此使用CustomStringConvertible协议。

From documentation,

从文档,

String(instance) will work for an instance of any type, returning its description if the instance happens to be CustomStringConvertible. Using CustomStringConvertible as a generic constraint, or accessing a conforming type's description directly, is therefore discouraged.

String(instance)将用于任何类型的实例,如果实例恰好是CustomStringConvertible的,则返回其描述。因此,不建议使用CustomStringConvertible作为通用约束,或者直接访问符合类型的描述。

So, if you conform to this protocol and return your rawValue through the description method, you will be able to use String(Table.User) to get the value.

因此,如果您遵循此协议并通过description方法返回rawValue,您将能够使用String(Table.User)来获取该值。

enum User: String, CustomStringConvertible {

    case Table = "User"
    case Username = "username"

    var description: String {
        return self.rawValue
    }
}

var myUser = [String: String]()
myUser[String(DatabaseKeys.User.Username)] = "Johnny"

print(myUser) // ["username": "Johnny"]

#3


2  

You can do this with custom class:

你可以通过定制类来实现:

enum Names: String {
    case something, thing
}

class CustomData {
    subscript(key: Names) -> Any? {
        get {
            return self.customData[key.rawValue]
        }

        set(newValue) {
            self.customData[key.rawValue] = newValue
        }
    }

    private var customData = [String: Any]()
}

...

let cData = CustomData()
cData[Names.thing] = 56

Edit:
I found an another solution, that working with Swift 3:

编辑:我找到了另一个解决方案,与Swift 3:

enum CustomKey: String {
    case one, two, three
}

extension Dictionary where Key: ExpressibleByStringLiteral {
    subscript(key: CustomKey) -> Value? {
        get {
            return self[key.rawValue as! Key]
        }
        set {
            self[key.rawValue as! Key] = newValue
        }
    }
}

var dict: [String: Any] = [:]
dict[CustomKey.one] = 1
dict["two"] = true
dict[.three] = 3
print(dict["one"]!)
print(dict[CustomKey.two]!)
print(dict[.three]!)

#4


0  

If you are able to use User as dictionary key instead of String (User is Hashable by default) it would be a solution.

如果您能够使用User作为字典键而不是String(默认情况下用户是可以清洗的),这将是一个解决方案。

If not you should use yours with a nested struct and static variables/constants.

如果不是,应该使用嵌套结构和静态变量/常量。

#1


16  

While I didn't find a way to do this using the desired syntax with enums, this is possible using structs.

虽然我没有找到一种方法来使用所需的枚举语法来实现这一点,但这是可以使用struct的。

struct DatabaseKeys {

    struct User {
        static let identifier = "User"
        static let Username = "username"
    }

}

To use:

使用方法:

myUser[DatabaseKeys.User.Username] = "Johnny"

Apple uses structs like this for storyboard and row type identifiers in the WatchKit templates.

Apple在WatchKit模板中对故事板和行类型标识符使用类似的结构。

#2


7  

You can use CustomStringConvertible protocol for this.

您可以为此使用CustomStringConvertible协议。

From documentation,

从文档,

String(instance) will work for an instance of any type, returning its description if the instance happens to be CustomStringConvertible. Using CustomStringConvertible as a generic constraint, or accessing a conforming type's description directly, is therefore discouraged.

String(instance)将用于任何类型的实例,如果实例恰好是CustomStringConvertible的,则返回其描述。因此,不建议使用CustomStringConvertible作为通用约束,或者直接访问符合类型的描述。

So, if you conform to this protocol and return your rawValue through the description method, you will be able to use String(Table.User) to get the value.

因此,如果您遵循此协议并通过description方法返回rawValue,您将能够使用String(Table.User)来获取该值。

enum User: String, CustomStringConvertible {

    case Table = "User"
    case Username = "username"

    var description: String {
        return self.rawValue
    }
}

var myUser = [String: String]()
myUser[String(DatabaseKeys.User.Username)] = "Johnny"

print(myUser) // ["username": "Johnny"]

#3


2  

You can do this with custom class:

你可以通过定制类来实现:

enum Names: String {
    case something, thing
}

class CustomData {
    subscript(key: Names) -> Any? {
        get {
            return self.customData[key.rawValue]
        }

        set(newValue) {
            self.customData[key.rawValue] = newValue
        }
    }

    private var customData = [String: Any]()
}

...

let cData = CustomData()
cData[Names.thing] = 56

Edit:
I found an another solution, that working with Swift 3:

编辑:我找到了另一个解决方案,与Swift 3:

enum CustomKey: String {
    case one, two, three
}

extension Dictionary where Key: ExpressibleByStringLiteral {
    subscript(key: CustomKey) -> Value? {
        get {
            return self[key.rawValue as! Key]
        }
        set {
            self[key.rawValue as! Key] = newValue
        }
    }
}

var dict: [String: Any] = [:]
dict[CustomKey.one] = 1
dict["two"] = true
dict[.three] = 3
print(dict["one"]!)
print(dict[CustomKey.two]!)
print(dict[.three]!)

#4


0  

If you are able to use User as dictionary key instead of String (User is Hashable by default) it would be a solution.

如果您能够使用User作为字典键而不是String(默认情况下用户是可以清洗的),这将是一个解决方案。

If not you should use yours with a nested struct and static variables/constants.

如果不是,应该使用嵌套结构和静态变量/常量。