1
votes

I have been trying to mix custom associated values with String in an Enum but not able to do so. When I try to apply a switch case over the enum, I get this error: Expression pattern of type 'Fruit' cannot match values of type 'Fruit'

Is it because Strings are value types and hence Swift is able to compare them but not custom class object of Fruit which is a reference type?

class Fruit{
    let name: String?
    let energyKcl: Double?
    let costPerKg: Double?

    init(name:String, energyKcl: Double, costPerKg: Double) {
        self.name = name
        self.energyKcl = energyKcl
        self.costPerKg = costPerKg
    }
}

enum Calorie {
    case fruit(Fruit)
    case chocolate (String)
    case dairy(String)
    case Nuts(String)
}


let banana = Fruit.init(name: "Banana", energyKcl: 100, costPerKg: 10)

func prepareBreakfast(calories: Calorie){
    switch calories {

    case .chocolate("Dark"):
        print("Dark")

    case .chocolate("White"):
        print("White")

    case .fruit(banana): //Error: Expression pattern of type 'Fruit' cannot match values of type 'Fruit'
        print("banana")

    default:
        print ("Not available")
    }
}

prepareBreakfast(calories: .fruit(banana))
3
Type should be Equatable for pattern matching.user28434'mstep
I'm not sure what the idea behind Calorie is, but it looks like it would be more appropriately modelled as a protocol with several conforming classes. This enum looks like the kind of thing you want to be able to expand in the future, and polymorphism does that better than tacking on new switch cases everywhere it's used.Alexander
Unrelated but why are all properties optional? They are constants and clearly initialized with non-optional values. The code compiles even without question marks. And you would get the == operator for free if Fruit was a struct and adopted Equatablevadian

3 Answers

2
votes

No the problem is that custom class isn't comparable without Equatable protocol

extension Fruit: Equatable {

    static func == (lhs: Fruit, rhs: Fruit) -> Bool {
        return lhs.name == rhs.name
        && lhs.energyKcl == rhs.energyKcl
        && lhs.costPerKg == rhs.costPerKg
    }

}
1
votes

Pattern matching uses Equatable internally, so you should change your Fruit class:

extension Fruit: Equatable {
    static func == (lhs: Fruit, rhs: Fruit) -> Bool {
        return lhs.name == rhs.name // or every field if you want
    }
}

If you want to use the reference, simply change the == func to return true if both references are equal, but I don't think it's a good idea:

static func == (lhs: Fruit, rhs: Fruit) -> Bool {
    return lhs === rhs
}
0
votes

In your code,

Replace the below line in prepareBreakfast(calories:) method,

case .fruit(banana):

with

case .fruit(let banana):

And you are good to go. I don't think there is any other issue with your code. It is working perfectly fine at my end.