【问题标题】:Access String value in enum without using rawValue在不使用 rawValue 的情况下访问枚举中的字符串值
【发布时间】:2015-08-30 16:52:51
【问题描述】:

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

结构如下:

enum DatabaseKeys {

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

    ...

}

数据库中的每个表都是一个内部枚举,表的名称是枚举的标题。每个枚举中的第一个 case 是表的名称,后面的 case 是它的表中的列。

要使用它,很简单:

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

但我会大量使用这些枚举。必须将.rawValue 附加到每个实例都会很痛苦,而且它不像我希望的那样可读。如何在不使用rawValue 的情况下访问字符串值?如果我能做到这一点,那就太好了:

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

请注意,我使用的是 Swift 2。如果有更好的方法来实现这一点,我很想听听!

【问题讨论】:

  • myUser是什么对象?字典还是你自己的带下标的对象?
  • @AndyIbanez 它可能是一个简单的字典,或者在我使用 Parse 时是一个 PFUser

标签: string swift enums swift2


【解决方案1】:

虽然我没有找到一种方法来使用所需的枚举语法来做到这一点,但使用结构是可能的。

struct DatabaseKeys {

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

}

使用方法:

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

Apple 将这样的结构用于 WatchKit 模板中的故事板和行类型标识符。

【讨论】:

    【解决方案2】:

    您可以为此使用 CustomStringConvertible 协议。

    来自文档,

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

    所以,如果你遵守这个协议,通过 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"]
    

    【讨论】:

    • 谢谢,这很有趣。尽管必须使用String 来初始化字符串同样低效。 :P 实际上,我宁愿使用rawValue,也不愿使用String()
    • 有没有办法使用 Int 类型的枚举来做到这一点?
    【解决方案3】:

    您可以在符合 String 的枚举上使用 callAsFunction(Swift 5.2 中的新功能)。

    enum KeychainKey: String {
       case userId
       case email
    }
    
    func callAsFunction() -> String {
        return self.rawValue
    }
    

    用法:

    KeychainKey.userId()
    

    【讨论】:

      【解决方案4】:

      您可以使用自定义类来做到这一点:

      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
      

      编辑:
      我找到了另一个解决方案,即使用 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]!)
      

      【讨论】:

      • 是否对所有继承自基类的枚举执行此操作?
      • 这仅用于将枚举用作字典键吗?
      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 2017-01-22
        • 1970-01-01
        • 2011-11-09
        • 2019-06-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-23
        相关资源
        最近更新 更多