WishIHadThreeGuns
WishIHadThreeGuns

Reputation: 1479

enum conformance to RawRepresentable

In the Swift book, the example for enums works fine

enum CompassPoint: String {
    case north, south, east, west
}

var northCom = CompassPoint.north
print (northCom)

However I want to use a failable initializer so made an example of this

enum WeekDay: String {
    case monday, tuesday, wednesday, thursday, friday
    init?(rawValue: Int){
        switch rawValue {
        case 0 : self = .monday
        case 1 : self = .tuesday
        case 2 : self = .wednesday
        case 3 : self = .thursday
        case 4 : self = .friday
        default : return nil
        }
    }
}

And get an error that Weekday does not conform to RawRepresentable - although I feel that conformance should be synthesized by the compiler so do not understand why this does not compile.

What I've done Created a similar working example (to see what the issue is), and still I want to conform to RawRepresentable using an enum with a failable initializer. I cannot find an example of this in the Swift book, in Stack Overflow questions or on the wider internet.

What I've provided Given a full example above, with the error as well as a working example of the behaviour I'm expecting.

What is not helpful Referencing the Swift book through a link or a comment is not helpful, as I've taken an example from there. I want to build on that example with a failable initializer. It is also not helpful to NOT use a enum, or a failable initializer. The question is about using a failable initalizer with a enum, and conforming to RawRepresentable. This is not homework, but those are the constraints of the question for my own learning and I'm interested in the outcome.

The question How can I use a failable initializer, with an enum as in the non-working example?

Upvotes: 13

Views: 24906

Answers (3)

Paul B
Paul B

Reputation: 5135

As of Swift 5 there is no error of having a second init?(rawValue: Int) in addition to synthesized init?(rawValue: String). But if you want to override that RawRepresantable implementation and have rawValue be Int, it is possible.

extension WeekDay : RawRepresentable {
    
    typealias RawValue = Int
    init?(rawValue: Int){
        switch rawValue {
        case 0 : self = .monday
        case 1 : self = .tuesday
        case 2 : self = .wednesday
        case 3 : self = .thursday
        case 4 : self = .friday
        default : return nil
        }
    }
    
    var rawValue: Int {
        switch self {
        case .monday : return 0
        case .tuesday :  return 1
        case .wednesday : return 2
        case .thursday : return 3
        case .friday : return 4
        }
    }
}
print(WeekDay.init(rawValue: 2)) // Optional(WeekDay.wednesday)
print(WeekDay.RawValue.self) // Int

Upvotes: 1

Y.Bonafons
Y.Bonafons

Reputation: 2359

"although I feel that conformance should be synthesized by the compiler"

Yes, here your rawValue is of type String, not Int. Simply create your enum like:

enum WeekDay: String {
    case monday, tuesday, wednesday, thursday, friday
}

And then create a WeekDay like this:

let monday: WeekDay? = WeekDay(rawValue: "monday")
let notADay: WeekDay? = WeekDay(rawValue: "foo")

Of course you can also add a custom init which takes an integer as argument:

enum WeekDay: String {
    case monday, tuesday, wednesday, thursday, friday
    init?(integer: Int){
        switch integer {
        case 0 : self = .monday
        case 1 : self = .tuesday
        case 2 : self = .wednesday
        case 3 : self = .thursday
        case 4 : self = .friday
        default : return nil
        }
    }
}

And create your weekDay like:

let monday: WeekDay? = WeekDay(integer: 0)
let notADay: WeekDay? = WeekDay(integer: 30)

Upvotes: 4

Martin R
Martin R

Reputation: 540135

Apparently your definition of init?(rawValue: Int) prevents the compiler from inferring the RawValue type automatically. Adding a type alias helps:

enum WeekDay: String {
    typealias RawValue = String

    case monday, tuesday, wednesday, thursday, friday

    init?(rawValue: Int){
        switch rawValue {
        case 0 : self = .monday
        case 1 : self = .tuesday
        case 2 : self = .wednesday
        case 3 : self = .thursday
        case 4 : self = .friday
        default : return nil
        }
    }
}

Alternatively define your custom init function with a different parameter name:

enum WeekDay: String {

    case monday, tuesday, wednesday, thursday, friday

    init?(rawInt: Int){
        switch rawInt {
        case 0 : self = .monday
        case 1 : self = .tuesday
        case 2 : self = .wednesday
        case 3 : self = .thursday
        case 4 : self = .friday
        default : return nil
        }
    }
}

Upvotes: 15

Related Questions