在 Swift 中使用具有关联值的枚举是否违反里氏替换原则?

Does using enum with associated value in Swift violate Liskov Substitution Principle?

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

我刚刚在 Swift 教程中看到了这一点,我无法相信他们允许您这样做。现在,每当我打开那个枚举时,我都要为 cloudy!

创建一个特例

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

事实并非如此,原因如下:

  • 您可以忽略 cloudy,将其与 default
  • 捆绑在一起
  • 模式匹配 可让您阅读 cloudycoverage 属性,同时将 cloudy 本身视为一个案例。
  • 当您阅读 属性 coverage 时,您可以选择忽略它或采取行动。

这里有一些例子:

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.")
...
}

Liskov Substitution Principle 与子类化有关。枚举不允许子类化,因此在这里不适用。

我不确定你反对为 cloudy 创建一个特例的原因是什么;如果您想专门处理这种情况,则无论如何都必须在 switch 中这样做。获取关联值的额外语法非常简单。

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)")
}

你什么都不"gotta"做。如果您不关心承保范围是什么,就不要问承保范围是什么。不在乎阴天,就别问阴天。为具有关联值的案例编写开关的方式没有什么特别之处。

假设我们有这个:

let weather = WeatherType.cloudy(coverage:1)

那么这是完全合法的:

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

这也是!

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

也没有任何法律要求您编写 switch 语句。如果你只是想知道weather是否是.cloudy,只要问:

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

如果您确实碰巧想知道coverage是什么,您仍然不需要编写 switch 语句:

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")
}

不能做的是应用==。这不会编译:

if weather == .sunny { // error

就此而言,是的,具有关联值的枚举与没有关联值的枚举的行为不同(如果这是您要问的)。