How to Make a Function to Accept Any Enum Types That Have a Rawvalue of String

Is there a way to make a function to accept any Enum types that have a rawValue of String?

There is already the RawRepresentable protocol which does what you want.

And you can extend based on whether RawValue == String

How to write a generic function to convert any enum value to its string representation?

You need to add a constraint to the 2nd parameter : T[keyof T] instead of number.

Also note that the key of your enum is of type string.

function enumToString<T extends { [name: string]: number | string }>(myenum: T, myenumvalue: T[keyof T]) {
return myenum[myenumvalue];
}

Playground

How do you declare an argument of type 'enum' (i.e. it can take any enum)?

Following Wain's suggestion, you can write something like this:

enum FirstEnum: String
{
case
A,
B,
C
}

enum SecondEnum: String
{
case
D,
E,
F
}

//create a protocol
public protocol StringKeyEnum {
var rawValue: String {get}
}
//make the enumeration(s) conform to it
extension FirstEnum: StringKeyEnum {}
extension SecondEnum: StringKeyEnum {}

var myDictionary: [String: AnyObject] = [:]
//use it in your interface definitions
public func storeValue(key: StringKeyEnum, value: AnyObject)
{
myDictionary[key.rawValue] = value //<-- Uses the rawValue of enum as a key
}
let someItem = ""
storeValue(FirstEnum.A, value: someItem) // Using the first enum type
storeValue(SecondEnum.D, value: someItem) // Using the second enum type
storeValue("Sam", value: someItem) // Won't compile since 'Sam' is not a StringKeyEnum

How to enumerate an enum with String type?

Swift 4.2+

Starting with Swift 4.2 (with Xcode 10), just add protocol conformance to CaseIterable to benefit from allCases. To add this protocol conformance, you simply need to write somewhere:

extension Suit: CaseIterable {}

If the enum is your own, you may specify the conformance directly in the declaration:

enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }

Then the following code will print all possible values:

Suit.allCases.forEach {
print($0.rawValue)
}


Compatibility with earlier Swift versions (3.x and 4.x)

If you need to support Swift 3.x or 4.0, you may mimic the Swift 4.2 implementation by adding the following code:

#if !swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif

SOLVED - Swift Enum - Casting Nested Enums to String Enum to allow .rawValue

Here is a solution that is not based on Item being an enum but instead a generic struct

struct Item<T: RawRepresentable> where T.RawValue == String {
let thing: T

var rawValue: String {
thing.rawValue
}
}

With this solution you don't need to change your other enums.
Example

let item1 = Item(thing: AnimalId.cat)
let item2 = Item(thing: VehicleId.car)
print(item1.rawValue, item2.rawValue)

outputs

cat car

generics type constraining for raw value in enums

If the intention is that the function accepts any enumeration type whose raw value is a string then this can be achieved with

func someFunc1<T: CaseIterable & RawRepresentable>(ofType: T.Type) where T.RawValue == String {
for aCase in T.allCases {
let someString: String = aCase.rawValue
print(someString)
}
}

someFunc1(ofType: SomeEnum.self)
// Hello
// How are you?

How to get enum from raw value in Swift?

Too complicated, just assign the raw values directly to the cases

enum TestEnum: String {
case Name = "Name"
case Gender = "Gender"
case Birth = "Birth Day"
}

let name = TestEnum(rawValue: "Name")! //Name
let gender = TestEnum(rawValue: "Gender")! //Gender
let birth = TestEnum(rawValue: "Birth Day")! //Birth

If the case name matches the raw value you can even omit it

enum TestEnum: String {
case Name, Gender, Birth = "Birth Day"
}

In Swift 3+ all enum cases are lowercased

Can a Swift enum have a function/closure as a raw value?

It's not as straight forward, but you could use OptionSet, see this page:

Unlike enumerations, option sets provide a nonfailable init(rawValue:) initializer to convert from a raw value, because option sets don’t have an enumerated list of all possible cases. Option set values have a one-to-one correspondence with their associated raw values.

Could be something like this:

func doSomething() {}
func doSomethingElse() {}

struct MyClosures: OptionSet {

static let closureOne = MyClosures(rawValue: doSomething)
static let closureTwo = MyClosures(rawValue: doSomethingElse)

let rawValue: () -> Void

init(rawValue: @escaping () -> Void) {
self.rawValue = rawValue
}

init() {
rawValue = {}
}

mutating func formUnion(_ other: __owned MyClosures) {
// whatever makes sense for your case
}

mutating func formIntersection(_ other: MyClosures) {
// whatever makes sense for your case
}

mutating func formSymmetricDifference(_ other: __owned MyClosures) {
// whatever makes sense for your case
}

static func == (lhs: MyClosures, rhs: MyClosures) -> Bool {
// whatever makes sense for your case
return false
}
}

And so you can use it as:

let myClosures: MyClosures = [ .closureOne, .closureTwo ]

HOWEVER looking at your explanation in the comment:

So I'm trying to find the most efficient way to run a function given the state of a variable.

I think what you actually want is some sort of state machine. Some examples are available here and here



Related Topics



Leave a reply



Submit