Swift 开关盒中的静态变量

Swift static var in switch case

switch-case 用于比较 static vars 未按预期工作。但是,指定类型或直接比较是可行的。请看下面:

class AnimalHelper {
    func loadAnimal(_ animal: Animal) {

        // Doesn't compile
        switch animal {
            case .squirrel, .deer: loadGrass()
            case .dolphin: return // not implemented
            default: loadMeat()
        }

        // Direct comparison works
        if animal == .squirrel || animal == .deer {
            loadGrass()
        } else if animal == .dolphin {
            return // not implemented
        } else {
            loadMeat()
        }

        // Specifying the type explicitly also works
        switch animal {
            case Animal.squirrel, Animal.deer: loadGrass()
            case Animal.dolphin: return // not implemented
            default: loadMeat()
        }
    }

    func loadGrass() {}
    func loadMeat() {}
}

class Animal {
    let id = 6 // Will be generated
    let hasFourLegs = true
    let numberOfEyes = 2
    // ... //

    static var squirrel: Animal { return .init() }
    static var dolphin: Animal  { return .init() }
    static var puma: Animal { return .init() }
    static var deer: Animal { return .init() }
}

extension Animal: Equatable {
    public static func ==(lhs: Animal, rhs: Animal) -> Bool {
        return lhs.id == rhs.id
    }
}

我确定上面的某些内容不太正确,因为我收到以下编译错误:

Enum case 'squirrel' not found in type 'Animal'
Enum case 'deer' not found in type 'Animal'
Enum case 'dolphin' not found in type 'Animal' 

请告诉我在 switch-case 条件下检查相等性与在 if 条件下检查相等性有何不同。

在 Swift 中,switch-case 可以使用几种不同的规则来匹配 switch 值和 case 标签:

  • enum 大小写匹配

    在这种情况下,您可以使用点引导的大小写标签,但不幸的是,您的 Animal 不是 enum

    (这与下面的 equality 不同,因为 enum 个案例可能具有关联值。)

  • 模式匹配运算符~=

    Swift 搜索 switch 值类型和 case 标签类型的重载,如果找到,则应用运算符并使用 Bool 结果表示 匹配 。 为此,Swift 需要独立于 switch- 值推断 case- 标签的类型,因此 Swift 无法推断 case- 的类型带点符号的标签。

  • 平等==

    switch 值为 Equatable 时,Swift 使用相等运算符 ==switch 值与 case-标签。

(可能还有很多想不起来了)

详细的行为没有明确定义,但编译器很难解决两个规则——模式匹配相等。 (您可能希望使用 ~=Equatable 类型定义自定义匹配。)

因此,在 Swift 3 中,case 标签中的点引导符号仅适用于 enum 类型。

但是,据我检查,Swift 4 人成功了。试试 Xcode 9(目前最新的是 beta 3),你的代码就会编译。此行为可能会在 Xcode 9 的发行版中发生变化,但您知道如何解决。