提取 Swift 枚举关联值



我想这样做...

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

你可以做这样的事情:

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 文档(中是禁止的。

我不确定您要执行的操作与类型转换有何不同。

如果您有:

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

感谢Cabus!!我稍微改变了它,以避免机箱上的凌乱开关

不确定这是否适用于泛型。我没有尝试,因为我想限制类型,并且没有看到将显式限制为我需要的类型的方法。

它也不是完美的,因为我必须在使用 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)")

感谢任何改进建议。

这是我使用泛型的解决方案。

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)

恕我直言,它现在不那么混乱,更具可读性,并且可以满足您的需求。

最新更新