The following code (compiles without errors) retrieves index of an element in a particular CaseIterable enum type
public enum MyEnum : CaseIterable {
case ONE, TWO, THREE
public func ordinal() -> Int? {
return MyEnum.allCases.firstIndex(of: self)
}
}
I want to make a generic function to work with all CaseIterable enums.
If I try:
public extension CaseIterable {
public func ordinal() -> Int? {
return CaseIterable.allCases.firstIndex(of: self)
}
}
I get a compiler error "Member 'allCases' cannot be used on value of protocol type 'CaseIterable'; use a generic constraint instead
" which is quite logical, as the actual enum type is unknown".
When I try CaseIterable<T>
, I get another error, as CaseIterable is not declared as generic type.
Is there a way?
To enable it, all you need to do is make your enum conform to the CaseIterable protocol and at compile time Swift will automatically generate an allCases property that is an array of all your enum's cases, in the order you defined them.
A type that provides a collection of all of its values.
An enum cannot have both raw values and associated values at the same time. The raw values of an enum must be of the same data type. But associated values can be of any type.
Couple of changes are necessary:
Self.AllCases.Index?
rather than Int?
. In practice, these types will be equivalent, as seen below.Equatable
, because you need to be equatable in order to use firstIndex(of:)
. Again, in practice, any CaseIterable
will usually be an enum without associated values, meaning it will be equatable automatically.nil
, because you're finding one case in a CaseIterable
. So you can remove the optionality on the return type (Self.AllCases.Index
) and force unwrap.Example:
public extension CaseIterable where Self: Equatable {
public func ordinal() -> Self.AllCases.Index {
return Self.allCases.firstIndex(of: self)!
}
}
enum Example: CaseIterable {
case x
case y
}
Example.y.ordinal() // 1
type(of: Example.y.ordinal()) // Int
Personally, I'd add that "Ordinal" usually means something different than what you're doing, and I'd recommend changing the function name to elementIndex()
or something. But that's an aside.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With