【问题标题】:Accessing an Enumeration association value in Swift在 Swift 中访问枚举关联值
【发布时间】:2014-06-17 12:14:57
【问题描述】:

在这段代码中,我编写了一个非常无用的枚举,它用 Int 或 Float 定义了一个可能的 Number

我不明白如何访问我通过关联设置的值。如果我尝试打印它,我只会得到(Enum Value)

enum Number {
    case int (Int)
    case float (Float)
}

let integer = Number.int(10)
let float = Number.float(10.5)
println("integer is \(integer)")
println("float is \(float)")

【问题讨论】:

  • @MikePollard 不是。他们只能通过 switch 访问值。
  • 我认为这是唯一的方法......
  • @MikePollard 这有点奇怪:P 但它可能对枚举的性质(及其用法)有意义。
  • 也许你想写一个函数,例如。 fund getInt() -> Int? { switch self{ case .int(let n) : return n default: return nil ...

标签: swift


【解决方案1】:

为了完整起见,枚举的关联值也可以使用带有模式匹配的 if 语句来访问。这是原始代码的解决方案:

enum Number {
  case int (Int)
  case float (Float)
}

let integer = Number.int(10)
let float = Number.float(10.5)

if case let .int(i) = integer {
  print("integer is \(i)")
}
if case let .float(f) = float {
  print("float is \(f)")
}

这个方案详细描述在:https://appventure.me/2015/10/17/advanced-practical-enum-examples/

【讨论】:

  • 替代语法:if case .int(let i) = integer { ... }
【解决方案2】:

该值与枚举的一个实例相关联。因此,要在没有开关的情况下访问它,您需要创建一个 getter 并使其显式可用。如下所示:

enum Number {
    case int(Int)
    case float(Float)

    func get() -> NSNumber {
        switch self {
        case .int(let num):
            return num
        case .float(let num):
            return num
        }
    }
}

var vInteger = Number.int(10)
var vFloat = Number.float(10.5)

println(vInteger.get())
println(vFloat.get())

也许将来会自动创建类似的东西,或者可以在语言中添加更短的便利。

【讨论】:

    【解决方案3】:

    让我感到惊讶的是 Swift 2(从 beta 2 开始)没有解决这个问题。以下是目前解决方法的示例:

    enum TestAssociatedValue {
      case One(Int)
      case Two(String)
      case Three(AnyObject)
    
      func associatedValue() -> Any {
        switch self {
        case .One(let value):
          return value
        case .Two(let value):
          return value
        case .Three(let value):
          return value
        }
      }
    }
    
    let one = TestAssociatedValue.One(1)
    let oneValue = one.associatedValue() // 1
    let two = TestAssociatedValue.Two("two")
    let twoValue = two.associatedValue() // two
    
    class ThreeClass {
      let someValue = "Hello world!"
    }
    
    let three = TestMixed.Three(ThreeClass())
    let threeValue = three. associatedValue() as! ThreeClass
    print(threeValue.someValue)
    

    如果您的枚举混合了带有和不带有关联值的大小写,则需要将返回类型设为可选。您还可以在某些情况下(没有关联值)返回文字,模仿原始值类型的枚举。您甚至可以为非关联、非原始类型的情况返回枚举值本身。例如:

    enum TestMixed {
      case One(Int)
      case Two(String)
      case Three(AnyObject)
      case Four
      case Five
    
      func value() -> Any? {
        switch self {
        case .One(let value):
          return value
        case .Two(let value):
          return value
        case .Three(let value):
          return value
        case .Four:
          return 4
        case .Five:
          return TestMixed.Five
        }
      }
    }
    
    let one = TestMixed.One(1)
    let oneValue = one.value() // 1
    let two = TestMixed.Two("two")
    let twoValue = two.value() // two
    
    class ThreeClass {
      let someValue = "Hello world!"
    }
    
    let three = TestMixed.Three(ThreeClass())
    let threeValue = three.value() as! ThreeClass
    print(threeValue.someValue)
    
    let four = TestMixed.Four
    let fourValue = four.value() // 4
    
    let five = TestMixed.Five
    let fiveValue = five.value() as! TestMixed
    
    switch fiveValue {
    case TestMixed.Five:
      print("It is")
    default:
      print("It's not")
    }
    // Prints "It is"
    

    【讨论】:

      【解决方案4】:

      喜欢@iQ。回答,你也可以在枚举中使用属性

      enum Number {
          case int (Int)
          var value: Int {
              switch self {
                  case .int(let value):
                      return value
              }
          }
      }
      
      let integer = Number.int(10)
      println("integer is \(integer.value)")
      

      【讨论】:

        【解决方案5】:

        我用过这样的东西:

        switch number {
        case .int(let n):
            println("integer is \(n)")
        case .float(let n):
            println("float is \(n)")
        }
        

        【讨论】:

        • 我想直接访问该值,而不是通过开关。
        • @MatterGoal - 你如何在不知道它是什么的情况下访问它?据我所知,开关是唯一的方法。
        • @MatterGoal - 正如 manojids 指出的那样,任何访问关联值的尝试都必须与检查枚举大小写相关联,因此开关实际上没有添加任何代码,可能会移动它一点就够了。
        • @MatterGoal “你怎么能在不知道它是什么的情况下访问它?据我所知,开关是唯一的方法。” - if 语句怎么样?能够针对一个特定的case 进行测试并在匹配时提取相关值,真是太好了。
        • @NicolasMiari - 我添加了使用 if 语句提取的解决方案:stackoverflow.com/a/37159851/466677
        【解决方案6】:

        如果你使用了守卫,你可以这样写:

        enum Action {
            case .moveTab(index: Int)
        }
        
        guard let case .moveTab(index) = someAction else { return }
        

        【讨论】:

          【解决方案7】:

          您不仅可以通过 switch 访问枚举关联值!镜子来帮助我们

          让我们创建一个协议

          protocol MirrorAssociated {
              var associatedValues: [String: Any] { get }
          }
          
          extension MirrorAssociated {
              var associatedValues: [String: Any] {
                  var values = [String: Any]()
                  if let associated = Mirror(reflecting: self).children.first {
                      let children = Mirror(reflecting: associated.value).children
                      for case let item in children {
                          if let label = item.label {
                              values[label] = item.value
                          }
                      }
                  }
                  return values
              }
          }
          

          并像这样使用它:

          enum Test: MirrorAssociated {
              case test(value: String, anotherValue: Int)
          }
          

          现在我们可以在不使用 switch 的情况下访问任何关联的值:

          let test: Test = .test(value: "Test String", anotherValue: 1337)
          
          if let value = test.associatedValues["value"] as? String {
              print("\(value)") // "Test String"
          }
          
          if let intValue = test.associatedValues["anotherValue"] as? Int {
              print("\(intValue)") // 1337
          }
          

          【讨论】:

            【解决方案8】:

            斯威夫特 5

            enum Directory {
                case accountImages(URL)
                case accountData(URL)
                
                var url: URL {
                    switch self {
                    case .accountImages(let url):
                        return url
                    case .accountData(let url):
                        return url
                    }
                }
            }
            
            func save(to directory: Directory) {
                let dir = directory.url
            }
            

            【讨论】:

              【解决方案9】:

              斯威夫特 4,

              我创建了一个简单的枚举,其中包含用于处理 firebase 数据库引用路径的关联值

              import Firebase
              
                  enum FirebaseDBConstants  {
              
                      case UserLocation(database : DatabaseReference, userID :String)
                      case UserRequest(database : DatabaseReference, requestID :String)
              
                      func getDBPath() -> DatabaseReference {
                          switch self {
                          case  .UserLocation(let database,let userID):
                              return database.root.child(FirebaseDBEnvironmentEnum.getCurrentEnvioronMent()).child("Location").child(userID).child("JSON")
              
                          case .UserRequest(let database,let requestID):
                              return database.root.child(FirebaseDBEnvironmentEnum.getCurrentEnvioronMent()).child("Request").child(requestID)
              
                          default:
                              break
                          }
                      }
                  }
              

              如图所示使用它

              //Pass Database refenence root as parameter with your request id
              let dbPath = FirebaseDBConstants.UserRequest(database: database, requestID: requestId).getDBPath()
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-09-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-06-16
                相关资源
                最近更新 更多