Swift中的枚举变量?

时间:2015-02-08 12:26:06

标签: swift enums

我想以通用的方式将多个值与枚举值相关联。

这可以用Java完成:

enum Test {

    A("test", 2);

    final String var1;
    final int var2;

    Test (String var1, int var2) {
        this.var1 = var1;
        this.var2 = var2;
    }
}

 public static void main(String []args){
    Test test = Test.A;
    System.out.println(test.var1);
 }

但看起来Swift是不可能的?到目前为止,根据docs,有:

  1. 相关值。示例(来自docs):

    enum Barcode {
        case UPCA(Int, Int, Int, Int)
        case QRCode(String)
    }
    

    但这不是我需要的。

  2. 原始价值。示例(来自docs):

    enum ASCIIControlCharacter: Character {
        case Tab = "\t"
        case LineFeed = "\n"
        case CarriageReturn = "\r"
    }
    

    这就是我需要的,但它只能有一个值!

  3. 这是一个优雅的解决方案......?似乎是一种语言设计决策,因为它会与相关的价值概念发生冲突,至少在目前的形式中如此。我知道我可以使用例如一个字典,用于将枚举值映射到其余部分,但在一个安全的步骤中确实缺少这样做,就像在Java中一样。

2 个答案:

答案 0 :(得分:17)

对于Swift enum,您只能使用(String|Integer|Float)LiteralConvertible类型作为原始值。如果您想使用现有类型(例如CGPoint)作为原始值,则应遵循@Alex答案。

我将在这个答案中提供两个备选方案

非常简单的解决方案

enum Test: String {
    case A = "foo:1"
    case B = "bar:2"

    var var1: String {
        return split(self.rawValue, { $0 == ":" })[0]
    }
    var var2: Int {
        return split(self.rawValue, { $0 == ":" })[1].toInt()!
    }
}

let test = Test.A
println(test.var1) // -> "foo"
你不喜欢这个吗?转到下一个:)

使用structstatic常量

的行为模拟
struct Test {
    let var1: String
    let var2: Int
    private init(_ var1:String, _ var2:Int) {
        self.var1 = var1
        self.var2 = var2
    }
}

extension Test {
    static let A = Test("foo", 1)
    static let B = Test("bar", 2)
    static let allValues = [A, B]
}

let test = Test.A
println(test.var1) // -> "foo"

但当然,struct缺少enum的某些功能。你必须手动实现它。

Swift enum隐式符合Hashable协议。

extension Test: Hashable {
    var hashValue:Int {
        return find(Test.allValues, self)!
    }
}

func ==(lhs:Test, rhs:Test) -> Bool {
    return lhs.var1 == rhs.var1 && lhs.var2 == rhs.var2
}

Test.A.hashValue // -> 0
Test.B.hashValue // -> 1
Test.A == Test.B // -> false

在第一个代码中,我们已经有allValues与Java中的values()相对应。 Java中的valueOf(...)相当于Swift中init?(rawValue:)协议中的RawRepresentable

extension Test: RawRepresentable {

    typealias RawValue = (String, Int)

    init?(rawValue: RawValue) {
        self.init(rawValue)
        if find(Test.allValues, self) == nil{
            return nil
        }
    }

    var rawValue: RawValue {
        return (var1, var2)
    }
}

Test(rawValue: ("bar", 2)) == Test.B
Test(rawValue: ("bar", 4)) == nil

等等......

我知道这不是“通用的”。我们永远无法模仿的一件事是Swift中的"Matching Enumeration Values with a Switch Statement"功能。你总是需要default案例:

var test = Test.A
switch test {
case Test.A: println("is A")
case Test.B: println("is B")
default: fatalError("cannot be here!")
}

答案 1 :(得分:1)

是的,这是一个设计决定,但在某些情况下你可以解决它。 我们的想法是将Type扩展为符合以下之一: integer-literal floating-point-literal string-literal

解决方案可以在这里找到 Bryan Chen's solution: How to create enum with raw type of CGPoint?

Sulthan在那里提出的第二个解决方案也可能是一种方法。