Compound switch cases: may we have a single common

2020-08-09 11:35发布

问题:

(As I prepared and almost finished writing up the question, re-reading the appropriate language guide section answered it for me, but possibly the Q&A can be of use for others, so I'll post it nonetheless)

Background

Consider the following enum, with cases that have one of two different types of associated values, Int or String:

enum Foo {
    case bar(Int)
    case baz(Int)
    case bax(Int)
    case fox(String)
}

When performing pattern matching in a switch statement, we may construct compound cases, each covering several possible matching patterns (entering the case branch if any of the patterns match):

func foo(_ foo: Foo) -> Int {
    switch foo {
        case .bar, .baz, .bax: return 42
        case .fox: return 0
    }
}

Just like non-compound cases, compound cases may also include value binding:

func foo(_ foo: Foo) -> Int {
    switch foo {
        case .bar(let x), .baz(let x), .bax(let x): return x 
        case .fox(let y): return Int(y) ?? 0
    }
}

// or
func foo(_ foo: Foo) -> Int {
    switch foo {
        case let .bar(x), let .baz(x), let .bax(x): return x 
        case let .fox(y): return Int(y) ?? 0
    }
}

Question

  • Is it possible to use a single common value binding for compound cases, which covers the compound of several enum cases that have the same type of associated value?

E.g., in the latter value binding examples above, some way to use a single binding functionality for the common-type associated value in the compound case

// not valid
func foo(_ foo: Foo) -> Int {
    switch foo {
        case .bar, .baz, .bax, (let x): return x 
        case .fox: return 0
    }
}

回答1:

No, this is not possible; in the value binding examples above, x must be bound in every pattern, and this must hold separately for every pattern in the compound cases.

Quoting the Language Guide - Control Flow [emphasis mine]

Compound cases can also include value bindings. All of the patterns of a compound case have to include the same set of value bindings, and each binding has to get a value of the same type from all of the patterns in the compound case. This ensures that, no matter which part of the compound case matched, the code in the body of the case can always access a value for the bindings and that the value always has the same type.

I we try to omit the binding in one of the patterns in the compound example above, we are given quite an self-explanatory error message on the subject:

func foo(_ foo: Foo) -> Int {
    switch foo {
        case .bar(_), .baz(let x), .bax(let x): return x 
        case .fox: return 0
    }
}
error: 'x' must be bound in every pattern

This holds even if we don't use x in the body that follows

func foo(_ foo: Foo) -> Int {
    switch foo {
        case .bar(_), .baz(let x), .bax(let x): return 0 
        case .fox: return 0
    }
} // same error