Does using enum with associated value in Swift vio

2019-05-31 05:36发布

问题:

enum WeatherType {
    case cloudy(coverage: Int)
    case sunny
    case windy
}

I just saw this in a Swift tutorial and I can't believe they allow you to do that. Now, whenever I switch on that enum, I gotta create a special case for cloudy!

回答1:

You don't "gotta" do anything. If you don't care what the coverage is, don't ask what the coverage is. If you don't care if it's cloudy, don't ask if it's cloudy. There is nothing special about the way you write a switch for a case that has an associated value.

Suppose we have this:

let weather = WeatherType.cloudy(coverage:1)

Then this is perfectly legal:

switch weather {
case .sunny:
    print("it is sunny")
default:
    print("I guess it's cloudy, or maybe windy")
}

And so is this!

switch weather {
case .cloudy:
    print("it is cloudy")
default:
    print("I guess it's sunny, or maybe windy")
}

Nor does any law require you to write a switch statement at all. If you simply want to know whether weather is .cloudy, just ask:

if case .cloudy = weather {
    print("yes it is cloudy")
} else {
    print("I guess it's sunny, or maybe windy")
}

And if you do happen to want to know what the coverage is, you still don't have to write a switch statement:

if case let .cloudy(cov) = weather {
    print("yes it is cloudy, in fact it is \(cov)")
} else {
    print("I guess it's sunny, or maybe windy")
}

What you cannot do is apply ==. This won't compile:

if weather == .sunny { // error

To that extent, yes, an enum with an associated value behaves differently from an enum without an associated value (if that's what you're asking).



回答2:

Now, whenever I switch on that enum, I gotta create a special case for cloudy!

That's not true, for several reasons:

  • You can ignore cloudy, bunching it with default, and
  • Pattern matching lets you read coverage property of cloudy, while treating cloudy itself as a single case.
  • When you read the property coverage you have an option to ignore it, or to act on it.

Here are some examples:

switch weatherType {
case .Cloudy(_):
    print("It is cloudy. I ignore the coverage.")
...
}

switch weatherType {
case .Cloudy(let coverage):
    print("It is cloudy. Coverage is \(coverage).")
...
}

switch weatherType {
case .Cloudy(let coverage) where coverage > 80:
    print("It is very cloudy.")
case .Cloudy(let coverage) where coverage < 20:
    print("It is slightly cloudy.")
case .Cloudy(_):
    print("It is cloudy.")
...
}


回答3:

The Liskov Substitution Principle has to do with subclassing. Enums do not allow subclassing, so it isn't applicable here.

I'm not sure what your objection is about creating a special case for cloudy; you have to do that anyway in a switch if you want to specifically handle that case. The extra syntax to grab the associated value is fairly straightforward.

let weather = WeatherType.cloudy(coverage: 17)

switch weather {
case .sunny:
    print("sunny")
case .windy:
    print("windy")
case .cloudy(let coverage):
    print("cloudy with coverage \(coverage)")
}