Variable variables in Swift?

I would like to associate several values ​​with the enumeration value in a general way.

This can be done in 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); } 

But it seems like this is not possible with Swift? So far, according to docs , there are:

  • Related Values. Example (from docs ):

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

    But that is not what I need.

  • The initial value. Example (from docs ):

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

    This will be what I need, but it can only have one meaning!

Is there an elegant solution for this ...? It looks like a solution for language design, because it contradicts the concept of related meanings, at least in its current form. I know that I can use, for example. a dictionary for matching enumeration values ​​for the rest, but this is actually not enough for one safe step, for example, in Java.

+6
source share
2 answers

For the Swift enum you can only use the (String|Integer|Float)LiteralConvertible as the source value. If you want to use an existing type (e.g. CGPoint ) for the raw value, you must follow CGPoint 's answer.

I will give 2 alternatives in this answer

Very simple solution

 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" 

Do you not like it? go to the next one :)

Emulating behavior using struct and static constants

 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" 

But, of course, struct lacks some functions from enum . You must manually implement it.

Swift enum implicitly conforms to the Hashable protocol.

 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 

In the first code, we already have allValues , which corresponds to values() in Java. valueOf(...) in Java is equivalent to init?(rawValue:) in the RawRepresentable protocol in Swift:

 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 

And so on...

I know that this is not "in a general sense." And one thing we can never emulate is the "Match enumeration values ​​using the switch statement" in Swift. you always need a default case:

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

Yes, this is a design decision, but in some cases you can get around it a bit. The idea is to extend the type so that it matches one of the following: integer-literal floating-point literal and string literal

The solution can be found here. Brian Chen's solution: How to create an enumeration with a raw CGPoint type?

The second solution presented by the Sultan may also be for you.

+1
source

Source: https://habr.com/ru/post/982167/


All Articles