在Swift中访问枚举关联值

Mat*_*oal 52 swift

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

我无法理解如何访问我使用关联设置的值.如果我尝试打印它,我会得到(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)")
Run Code Online (Sandbox Code Playgroud)

Mar*_*gor 73

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

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)")
}
Run Code Online (Sandbox Code Playgroud)

此解决方案详细描述于:https://appventure.me/2015/10/17/advanced-practical-enum-examples/

  • 替代语法:`if case .int(let i) = integer { ... }` (3认同)

iQ.*_*iQ. 72

该值与枚举的实例相关联.因此,要在没有开关的情况下访问它,您需要制作一个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())
Run Code Online (Sandbox Code Playgroud)

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

  • 这是不可扩展的。假设您有 20 个案例! (3认同)

Sco*_*ner 11

令我惊讶的是,Swift 2(截至测试版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)
Run Code Online (Sandbox Code Playgroud)

如果你的枚举混合了有和没有关联值的情况,你需要使返回类型成为可选.您还可以为某些情况(没有关联值)返回文字,模仿原始值类型的枚举.您甚至可以为非关联的非原始类型的案例返回枚举值本身.例如:

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"
Run Code Online (Sandbox Code Playgroud)


man*_*lds 8

我用过这样的东西:

switch number {
case .int(let n):
    println("integer is \(n)")
case .float(let n):
    println("float is \(n)")
}
Run Code Online (Sandbox Code Playgroud)

  • 我想直接访问该值,而不是通过开关。 (12认同)

小智 8

您不仅可以通过 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
    }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

enum Test: MirrorAssociated {
    case test(value: String, anotherValue: Int)
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以在不使用 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
}
Run Code Online (Sandbox Code Playgroud)


Zoo*_*ooz 6

喜欢@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)")
Run Code Online (Sandbox Code Playgroud)


And*_*rew 6

enum NumberEnum {
    case int(Int)
    case float(Float)
    case twoInts(Int, Int)
}

let someNum = NumberEnum.twoInts(10,10)
Run Code Online (Sandbox Code Playgroud)

要从 ValueAssociatedEnum 获取值,您可以采用以下 3 种方式之一:

方式一:

if case .twoInts( let val1, let val2 ) = someNum {
    print("hello \(val1) \(val2)")
}
Run Code Online (Sandbox Code Playgroud)

方式二:

guard case let .int(val) = someNum else { return }
print(val)
Run Code Online (Sandbox Code Playgroud)

方式三:

switch someNum {
case .int(let val):
    print("\(val)")
default:
    break;
}
Run Code Online (Sandbox Code Playgroud)

奖励:方式 4 - 镜像

最好不要使用镜像

  1. 它很慢。所以代码不利于生产。
  2. 如果出现一些错误,则很难调试。

但是您可以在 Ilia Kambarov 的回答中检查如何使用镜像来获取价值:/sf/answers/4858461331/

还有关于与值关联的枚举相关的镜像的有趣信息: 通用枚举关联值扩展。是否可以?