mfaani
mfaani

Reputation: 36427

pattern matching for strings

func swtiching (a: String, b: String){
    switch (a,b){
    case ("a", "b"): print("a and b")
    case (("a" || "c"), ("b" || "d")): print(" a or b and c or d")

    default: print("something else")
    }
}

If I do this, the 2nd case will give the following error:

cannot convert value of type 'String' to expected argument type 'Bool'

EDIT:

if "a" == "a" || "c"{
print("xyz")
}

This would also result in the same error.

Upvotes: 1

Views: 212

Answers (2)

Alexander
Alexander

Reputation: 63369

Here is what I would cook up:

struct DisjunctiveMatcher<T: Equatable> {
    let desired: [T]
    func matches(candidate: T) -> Bool { return desired.contains(candidate) }
}

func ~= <T: Equatable>(pattern: DisjunctiveMatcher<T>, candidate: T) -> Bool {
    return pattern.matches(candidate: candidate)
}

func oneOf<T: Equatable>(_ elements: T...) -> DisjunctiveMatcher<T> {
    return DisjunctiveMatcher(desired: elements)
}


func swtichingExample(a: String, b: String) {
    switch (a, b) {
    case ("a", "b"): print("a and b")
    case (oneOf("a", "b"), oneOf("b", "d")): print(" a or b and c or d")

    default: print("something else")
    }
}

If you realllllly want to achieve exactly the syntax you want, that's possible too, but I would strongly advise against it, because such a overload of || is quite unintuitive, and deviates from what people would expect. I'm just pointing out that it's possible:

/// Starts a chain of strings, where lhs and rhs are used to
/// define a DisjunctiveMatcher<String>
func || (lhs: String, rhs: String) -> DisjunctiveMatcher<String> {
    return DisjunctiveMatcher(desired: [lhs, rhs])
}

/// Extends an existing chain of strings, where rhs is added
/// to the desired strings of las
func || (lhs: DisjunctiveMatcher<String>, rhs: String) -> DisjunctiveMatcher<String> {
    return DisjunctiveMatcher(desired: lhs.desired + [rhs])
}

func crazySwitchingExample(a: String, b: String) {
    switch (a, b) {
    case ("a", "b"): print("a and b")
    case (("a" || "c"), ("b" || "d")): print("Go home, you're drunk. 🍻")

    default: print("something else")
    }
}

Upvotes: 3

David Pasztor
David Pasztor

Reputation: 54775

Using tuple patterns, if you want to match all combinations of different combinations of a being one of "a" or "c" and b being one of "b" or "d", as far as I know, if you don't to overload the pattern matching operators (~+), your only solution would be explicitly writing out all possible tuples (("a",b"),("a","d"),("c","b"),("c","d")), which is quite cumbersome even for 2 values.

I think using if statements and creating an array with all possible values for the variables, then calling [String].contains() is an easier solution for this case.

func switching (a: String, b: String){
    if a == "a", b == "b" {
        print("a and b")
    } else if ["a","c"].contains(a), ["b","d"].contains(b) {
        print(" a or b and c or d")
    } else {
        print("something else")
    }
}

switching(a: "a", b: "b") // print("a and b")
switching(a: "a", b: "d") // print(" a or b and c or d")

Upvotes: 1

Related Questions