I understand why I cannot extract the raw value from an enum that uses associated values, even for one of the statements, but why can I not extract the raw value from the enum that is one of the associated values themselves?
enum FoesLevel {
case pipsqueak (annimaux: PipsqueakFoes)
case average (annimaux: AverageFoes)
case tough (annimaux: ToughFoes)
}
enum PipsqueakFoes: String {
case spider = "Spider"
case beetle = "Beetle"
}
enum AverageFoes: String {
case mouse = "Mouse"
case squirrel = "Squirrel"
}
enum ToughFoes: String {
case snake = "Snake"
case gnome = "Gnome"
}
let test1 = FoesLevel.pipsqueak(annimaux: .spider).self
//print(test1.rawValue)
The FoesLevel enum does not have a rawValue property. You could define one yourself, or your could define a property with a more descriptive name. For example:
extension FoesLevel {
var name: String {
switch self {
case .pipsqueak(let x): return x.rawValue
case .average(let x): return x.rawValue
case .tough(let x): return x.rawValue
}
}
}
Just returning back to this now I found a way around this, Tiigi's solution is closer to what I was looking for as it returns an existing value, rather than having to put them back in again, which wouldn't make sense for what I wanted to achieve.
However, I don't believe that I was clear enough in the outset as from the example I gave I actually wanted to return the "spider" rawValue, not the enum's name. I did look into RawRepresentable, but I didn't understand it and looking at the code I am not able to understand what is going on to modify it.
If I understand you correctly, I think this is what you're looking for:
let test1 = FoesLevel.pipsqueak(annimaux: .spider).self
if case let FoesLevel.pipsqueak(annimaux) = test1 {
print(annimaux.rawValue) // "Spider"
}
// or
switch test1 {
case .pipsqueak(let annimaux):
print(annimaux.rawValue) // "Spider"
default:
break
}
You have to access the associated value of your FoesLevel case in order to get it's rawValue
As others have mentioned, you could also add RawRepresentable to FoesLevel:
enum FoesLevel: RawRepresentable {
case pipsqueak (annimaux: PipsqueakFoes)
case average (annimaux: AverageFoes)
case tough (annimaux: ToughFoes)
var rawValue: String {
switch self {
case .pipsqueak(let annimaux): return annimaux.rawValue
case .average(let annimaux): return annimaux.rawValue
case .tough(let annimaux): return annimaux.rawValue
}
}
init?(rawValue: String) {
if let pipsqueak = PipsqueakFoes(rawValue: rawValue) {
self = .pipsqueak(annimaux: pipsqueak)
}
else if let average = AverageFoes(rawValue: rawValue) {
self = .average(annimaux: average)
}
else if let tough = ToughFoes(rawValue: rawValue) {
self = .tough(annimaux: tough)
}
else {
return nil
}
}
}
print(FoesLevel.pipsqueak(annimaux: .spider).rawValue) // Spider
However personally I would recommend reversing the ownership here and have your Foes have a FoesLevel, rather than the FoesLevel containing the Foes
Thanks for the help GetSwifty, apologies for the late response. I did see the logic in what you proposed by reversing ownership, which actually fit better with what I needed, I think. However, I needed to further conform to Hashable and would like you to inspect my changes, let me know if they're ok please:
enum FoesLevel: RawRepresentable, Hashable {
case mouse (category: PipsqueakFoes)
case cat (category: AverageFoes)
case lion (category: ToughFoes)
var hashValue2 : String {
return self.toString()
}
func toString() -> String {
switch self {
case .mouse : return "Mouse"
case .cat : return "Cat"
case .lion : return "Lion"
}
}
var rawValue: String {
switch self {
case .mouse(let category): return category.rawValue
case .cat(let category): return category.rawValue
case .lion(let category): return category.rawValue
}
}
init?(rawValue: String) {
if let mouse = PipsqueakFoes(rawValue: rawValue) {
self = .mouse(category: mouse)
}
if let cat = PipsqueakFoes(rawValue: rawValue) {
self = .cat(category: cat)
}
if let lion = AverageFoes(rawValue: rawValue) {
self = .lion(category: lion)
}
else {
return nil
}
}
}
func == (lhs: FoesLevel, rhs: FoesLevel) -> Bool {
return lhs.toString() == rhs.toString()
}
For some reason Xcode warned me about a duplicate declaration of "hashValue" ("hashValue2"), but I couldn't find it anywhere in my code, is this normal?
Since your rawValue is a String, and String already conforms to Hashable, hashValue is synthesized for you when you declare that FoesLevel conforms to Hashable. You don't need to define it yourself.
I was hoping for the same, but when using the enum with a dictionary Swift kicked up a fuss. I am on v4x, but regardless I take it that I did it correctly?
I don't know for sure if that functionality was there in 4.x, but given the duplicate definition error you received, I assume that it was.
As for Swift having "kicked up a fuss", can you be more specific? What did you try to do and what was the actual error that you received?
Note, also, that your last bit of code above has some issues. Your init? method has a couple of type mismatch errors, and because you left out a few elses, even if the type errors are fixed, it will return nil for inputs of "Mouse" and "Cat" where it shouldn't. The init should probably look something like:
if let mouse = PipsqueakFoes(rawValue: rawValue) {
self = .mouse(category: mouse)
} else if let cat = AverageFoes(rawValue: rawValue) {
self = .cat(category: cat)
} else if let lion = ToughFoes(rawValue: rawValue) {
self = .lion(category: lion)
} else {
return nil
}
}
Beyond that, the init is fallible, so it returns a FoesLevel? rather than a FoesLevel. If you are trying to use it with a dictionary of type [FoesLevel: SomeOtherType] rather than [FoesLevel?: SomeOtherType] you will get errors if you try to use an optional as the key.