在switch之外访问swift enum case?

时间:2016-09-08 22:33:40

标签: swift enums swift3

我们说我有一个简单的Pet enum:

enum Pet {
    case dog(name:String)
    case cat(name:String)

    var name:String {
        switch self {
        case .dog(let name):
            return name
        case .cat(let name):
            return name
        }
    }
}

(它们具有相同类型的相关值并因此感觉多余的事实应该被忽略)

现在我希望能够将宠物等同起来。我可以写:

extension Pet:Equatable { }

func == (a:Pet, b:Pet) -> Bool {
    return a.name == b.name
}

但这将允许一只名为" Spots"等于名为" Spots"的狗。这不是我想要的。有没有一种简单的方法来访问枚举实例的情况?我们通常在switch语句中执行它们,但在这种情况下,我想要更直接的东西(一行),我可能需要在将来的Comparable扩展中使用它。

我可以自己做:

extension Pet {
    var petType:Int {
        switch self {
        case .dog:
            return 1
        case .cat:
            return 2
        }
    }
}

现在我可以将==实施更改为

func == (a:Pet, b:Pet) -> Bool {
    return a.petType == b.petType && a.name == b.name
}

是否有一些内置的Swift语法糖可以为我做同样的事情?我尝试了type(of:),但这只是返回Pet,没有关于实例的情况。

3 个答案:

答案 0 :(得分:2)

据我所知,Swift没有为我们提供仅检索案例标签的快捷方式。

在您的情况下,您可以使用name属性编写类似的内容:

extension Pet: Equatable {
    static func == (a: Pet, b: Pet) -> Bool {
        switch (a, b) {
        case (.dog, .dog), (.cat, .cat):
            return a.name == b.name
        default:
            return false
        }
    }
}

如果您的Pet没有name属性,则可以将其写为:

extension Pet: Equatable {
    static func == (a: Pet, b: Pet) -> Bool {
        switch (a, b) {
        case let (.dog(namea), .dog(nameb)),
             let (.cat(namea), .cat(nameb)):
            return namea == nameb
        default:
            return false
        }
    }
}

但在你的情况下,使用类层次结构是不是很自然?:

class Pet {
    var name: String
    init(name: String) {
        self.name = name
    }
}

class Dog: Pet {}
class Cat: Pet {}

extension Pet {
    static func dog(name: String) -> Pet {
        return Dog(name: name)
    }
    static func cat(name: String) -> Pet {
        return Cat(name: name)
    }
}

extension Pet: Equatable {
    static func == (a: Pet, b: Pet) -> Bool {
        return type(of: a) === type(of: b) && a.name == b.name
    }
}

答案 1 :(得分:1)

您可以这样做:

func ==(lhs: Pet, rhs: Pet) -> Bool {
    if case let Pet.cat(l) = lhs, case let Pet.cat(r) = rhs where l == r { return true }
    if case let Pet.dog(l) = lhs, case let Pet.dog(r) = rhs where l == r { return true }

   return false
}

switch可能看起来更好,而且更容易维护。

答案 2 :(得分:1)

我有一种混合方法,可以让事情更加模块化:

    enum Pet {

    case dog(name:String)
    case cat(name:String)

    var name: String {
        switch self {
        case .dog(let name):
            return name
        case .cat(let name):
            return name
        }
    }

    func equalCaseTo(otherPet: Pet) -> Bool {
        switch (self, otherPet) {
        case (.dog(_), .dog(_)), (.cat(_), .cat(_)):
            return true
        default:
            return false
        }
    }

    func equalNameTo(otherPet: Pet) -> Bool {
        return name == otherPet.name
    }
}

func ==(left:Pet, right:Pet) -> Bool {
    return left.equalCaseTo(right) && left.equalNameTo(right)
}