Есть ли способ написать выражение `if case` как выражение?

Рассмотрим этот код:

enum Type {
    case Foo(Int)
    case Bar(Int)

    var isBar: Bool {
        if case .Bar = self {
            return true
        } else {
            return false
        }
    }
}

Это грубо. Я хотел бы написать что-то вроде этого:

enum Type {
    case Foo(Int)
    case Bar(Int)

    var isBar: Bool {
        return case .Bar = self
    }
}

Но такая конструкция, похоже, не существует в Swift, или я не могу ее найти.

Так как есть данные, связанные с каждым случаем, я не считаю возможным реализовать оператор ~= (или любой другой помощник) таким образом, который эквивалентен приведенному выше выражению. И в любом случае, операторы if case существуют бесплатно для всех перечислений и не нуждаются в ручном внедрении.

Таким образом, мой вопрос: есть ли более сжатый/декларативный/чистый/идиоматический способ реализовать isBar, чем то, что у меня выше? Или, более прямо, есть ли способ выразить выражения if case как выражения Swift?

Ответы

Ответ 1

ОБНОВЛЕНИЕ 2: Другое обходное решение... Создайте var, который возвращает значение Int ТОЛЬКО на основе этого случая, а затем используйте статический (или экземпляр, я думал, статический, выглядящий более чистый) метод, чтобы проверить эквивалентность только этого случая. Он не будет сталкиваться с Equatable, вам не нужно перегружать оператора (если вы не хотите заменить статический метод на один), и вам также не нужно будет создавать отдельные var isFoo, var isBar, и др.

Я знаю, что вы использовали этот пример, чтобы задать более общий вопрос (как я могу использовать "if case" как выражение?), но если это невозможно, это может быть допустимым обходным путем. Я прошу прощения, если это относится к "симптомам", а не к "проблеме"

enum Something{
    case Foo(Int)
    case Bar(Int)

    static func sameCase(a: Something, b: Something) -> Bool {
        return a.caseValue == b.caseValue
    }

    var caseValue: Int {
        switch self {
        case .Foo(_):
            return 0
        case .Bar(_):
            return 1
        }
    }

    //if necessary
    var isBar: Bool {
        return Something.sameCase(self, b: Something.Bar(0))
    }
}

Something.sameCase(.Bar(0), b: .Foo(0)) // false
Something.sameCase(.Bar(1), b: .Foo(2)) // false
Something.sameCase(.Foo(0), b: .Foo(0)) // true
Something.sameCase(.Bar(1), b: .Bar(2)) // true


Something.Bar(0).isBar // true
Something.Bar(5).isBar // true
Something.Foo(5).isBar // false

ОБНОВЛЕНИЕ 1:

Хорошо, так что это работает. Если вы перегружаете оператор == для игнорирования значений и возвращаете true, только если оба перечисления являются одним и тем же случаем, вы можете передать любое значение в свой метод isFoo и все еще определить тип.

Я предполагаю, что вам нужно будет настроить эту функцию для размещения связанных значений, но это похоже на шаг в правильном направлении

enum Something {
    case Foo(Int)
    case Bar(Int)

    var isFoo: Bool {
        return self == .Foo(0) // number doesn't matter here... see below
    }
}

func ==(a: Something, b: Something) -> Bool {
    switch (a,b) {
    case (.Bar(_), .Bar(_)):
        return true
    case (.Foo(_), .Foo(_)):
        return true
    default:
        return false

    }
}

let oneFoo = Something.Foo(1)
let twoFoo = Something.Foo(2)
let oneBar = Something.Bar(1)
let twoBar = Something.Bar(2)

oneFoo == twoFoo // true
oneFoo == oneFoo // true
oneFoo == oneBar // false
oneFoo == twoBar // false

OLD:

Вы можете использовать self и имя case, чтобы напрямую проверить, в каком именно случае, вам не нужно использовать ключевое слово case. Надеюсь, это сработает для вашей ситуации:

enum Something{
    case Foo(Int)
    case Bar(Int)

    var isFoo: Bool {
        switch self {
        case Foo:
            return true
        case Bar:
            return false
        }
    }
}