提取Swift枚举关联值

时间:2018-02-04 22:08:03

标签: swift enums

我想这样做......

let myInt = E.i(420)
let myString = E.s("Crook")

......有了......

enum E {
  case i(Int?)
  case s(String?)

  func i() -> Int? { 
    // How do I implement?
  }

  func s() -> String? {
    // How do I implement?
  }
}

...所以我可以这样做......

let theInt = myInt.i()
let theString = myDouble.s()

......甚至更好,这样做......

let betterInt = myInt.i
let betterString = myString.s

......或者如果我想要在天堂......

let i = myInt // based on associated value return typed value as Int or nil
let i: Int = myInt // convert it automatically and return Int or nil

let s = myString // based on associated value return typed value as String or nil
let s: String = myString // convert it automatically and return String or nil

4 个答案:

答案 0 :(得分:1)

你可以这样做:

enum E {
  case i(Int?)
  case s(String?)

  var i: Int? {
    switch self {
    case .i(let value): return value
    case .s(_): return nil
    }
  }

  var s: String? {
    switch self {
    case .i(_): return nil
    case .s(let value): return value
    }
  }
}
可悲的是,你天上的解决方案并不可行。您必须重载=运算符,并且在Swift(Apple Documentation)中禁止此操作。

答案 1 :(得分:0)

我不确定你要做的是什么与类型演员不同。

如果你有:

let myInt = 420
let myString = "Crook"

然后

let i = myInt as? Int // makes i an Int? which would be nil if myInt didn't 
                      // actually contain an integer
                      // note that a non-optional Int would not accept a nil
                      // so heaven cannot work as you would expect

let s = mySting as? String // makes s a String? ...

您声明为E(...)的变量只需要声明为Any。

如果您想要特定的类型子集,您可以为它们定义协议并使用它而不是Any。

例如:

protocol E 
{}
extension Int:E {}
extension String:E {}

let myVariable:E = 3

let i = myVariable as? Int

您还可以扩展语法糖果的协议:

extension E
{
   var value:Int? { return self as? Int }
}

let i:Int? = myVariable.value

答案 2 :(得分:-1)

感谢Cabus !!!我稍微改了一下,以免乱开案件

不确定这适用于Generics。我没有尝试,因为我想限制类型,并没有看到明确限制我需要的类型的方法。

它也不完美,因为我必须在使用Int32和Double时明确告知编译器。并指定"键入" nil很笨拙。但是我可以忍受。

public enum D {
    case Int (Int32?)
    case Double (Double?)
    case String (String?)

    public init(_ i: Int32?) {
        self = .Int(i)
    }

    public init(_ d: Double?) {
        self = .Double(d)
    }

    public init(_ s: String?) {
        self = .String(s)
    }

    var int: Int32? {
        if case D.Int(let int) = self {  return int }
        return nil
    }
    var double: Double? {
        if case D.Double(let double) = self {  return double }
        return nil
    }
    var string: String? {
        if case D.String(let string) = self {  return string  }
        return nil
    }
}

测试代码......

let myInt = D(Int32(2))
let myString = D("Two")
let myDouble = D(Double(2.0))
let myIntOptional = D.Int(nil) // when wanting to use "typed" nil

print("myInt = \(myInt.int)")
print("myString = \(myString.string)")
print("myDouble = \(myDouble.double)")
print("myIntOptional = \(myIntOptional.int)")

欣赏任何改进建议。

答案 3 :(得分:-1)

所以这是我使用Generics的解决方案。

public enum E<T> {
    case Value (T)

    public init (_ t: T) {
        self = .Value(t)
    }

    var value: T {
        switch self {
        case .Value(let t): return t
        }
    }
}

测试代码......

let myInt = E<Int32>(2)
let myString = E<String>("Two")
let myDouble = E<Double>(2)
let myDate = E<Date>(Date())
let myIntOptional = E<Int32?>(nil)
let myIntOptionalWithValue = E<Int32?>(4444)

print("myInt = \(myInt.value)")
print("myString = \(myString.value)")
print("myDouble = \(myDouble.value)")
print("myDate= \(myDate.value)")
print("myIntOptional = \(myIntOptional.value)")
print("myIntOptionalWithValue = \(myIntOptionalWithValue.value)")

测试结果......

myInt = 2
myString = Two
myDouble = 2.0
myDate= 2018-02-05 02:52:51 +0000
myIntOptional = nil
myIntOptionalWithValue = Optional(4444)
恕我直言,它现在不那么凌乱,更具可读性,能够满足我的需求。