In Swift, when an enum
conforms to CaseIterable
, "The synthesized allCases collection provides the cases in order of their declaration."
I would like to sort an array of CaseIterable
enum cases, which means conforming to Comparable
. Can I access this same order of declaration to determine how such objects should be sorted?
If not, is my implementation of <
below reasonable?
enum MyEnum: CaseIterable, Comparable {
case one, two, three
}
static func < (lhs: MyEnum, rhs: MyEnum) -> Bool {
guard let lhsIndex = allCases.firstIndex(of: lhs), let rhsIndex = allCases.firstIndex(of: rhs) else {
fatalError("`MyEnum`'s implementation of `Comparable.<` found a case that isn't present in `allCases`.")
}
return lhsIndex < rhsIndex
}
Finally, is it possible to go one step further and make CaseIterable
itself conform to Comparable
this way? Any reason this would be a bad idea?
In Swift 5.3 and later you can use the synthesized conformance to Comparable
for any enum that either has no associated value or has an associated value that conforms to Comparable
.
For example:
enum Size: Comparable {
case small
case medium
case large
case extraLarge
}
let shirtSize = Size.small
let personSize = Size.large
if shirtSize < personSize {
print("That shirt is too small")
}
I have an article providing information on this change, along with other features introduced in Swift 5.3: What’s new in Swift 5.3?
If you don't want to make your enum
conform to RawRepresentable
with an Int
RawValue
type, like the other answers here have posted, then your approach seems reasonable to me.
As for this question:
Finally, is it possible to go one step further and make
CaseIterable
itself conform toComparable
this way?
Yes, you could make an extension on Comparable
that contains a default implementation of the <
function and constrain the extension to only apply when Self
also conforms to CaseIterable
, as shown below:
extension Comparable where Self: CaseIterable {
static func < (lhs: Self, rhs: Self) -> Bool {
guard let lhsIndex = allCases.firstIndex(of: lhs), let rhsIndex = allCases.firstIndex(of: rhs) else {
fatalError("`\(Self.self)`'s implementation of `Comparable.<` found a case that isn't present in `allCases`.")
}
return lhsIndex < rhsIndex
}
}
This will give this <
function to any enum you declare as conforming to both Comparable
and CaseIterable
.
You could make the enum accessed in the same order as the declaration by providing an Int
raw type to your enum:
enum MyEnum: Int, CaseIterable {
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