Как заставить enum соответствовать Hashable с API, доступным в Xcode 10? - PullRequest
0 голосов
/ 04 января 2019

В моем коде Swift 4.2.1 у меня есть это перечисление:

enum MyEnum {

    case caseOne(Int)
    case caseTwo(String)
    case caseThree
}

Соответствует Equatable:

extension MyEnum: Equatable {

    static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {

        switch (lhs, rhs) {
        case (.caseOne, .caseOne), (.caseTwo, .caseTwo), (.caseThree, .caseThree):
            return true
        default:
            return false
        }
    }
}

Мне нужно, чтобы он соответствовал Hashable, поэтому я добавил расширение:

extension MyEnum: Hashable {

    var hashValue: Int {

        switch self {
        case .caseOne:
            return 1
        case .caseTwo:
            return 2
        case .caseThree:
            return 3
        }
    }
}

Теперь я хочу перейти на новый API, доступный в Xcode 10. Я удалил свою реализацию hashValue и добавил реализацию hash(into:):

extension MyEnum: Hashable {

    func hash(into hasher: inout Hasher) {

        switch self {
        case .caseOne:
            hasher.combine(1)
        case .caseTwo:
            hasher.combine(2)
        case .caseThree:
            hasher.combine(3)
        }
    }
}

Не могли бы вы сказать, правильно ли я переключился на новый API? Я использую этот тест, он печатает true дважды, если все работает нормально:

var testDictionary = [MyEnum: Int]()
testDictionary[.caseOne(100)] = 100
testDictionary[.caseOne(1000)] = 1000
testDictionary[.caseTwo("100")] = 100
testDictionary[.caseTwo("1000")] = 1000
let countCaseOne = testDictionary.reduce(0) {
    if case .caseOne = $1.key {
        return $0 + 1
    }
    return $0
} == 1
print(countCaseOne) // true
let countCaseTwo = testDictionary.reduce(0) {
    if case .caseTwo = $1.key {
        return $0 + 1
    }
    return $0
} == 1
print(countCaseTwo) // true

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Вы можете использовать автоматически сгенерированное соответствие Hashable, как предложено в другом ответе (при условии, что ваш тип не содержит никакой даты не Hashable типов).

Но это то, что вы можете сделатьв общем случае (сгенерированный код, вероятно, тоже будет выглядеть так):

extension MyEnum: Hashable {

    func hash(into hasher: inout Hasher) {

        switch self {
        case .caseOne(let value):
            hasher.combine(value) // combine with associated value, if it's not `Hashable` map it to some `Hashable` type and then combine result
        case .caseTwo(let value):
            hasher.combine(value) // combine with associated value, if it's not `Hashable` map it to some `Hashable` type and then combine result
        case .caseThree:
            // you can `combine` with some `Hashable` constant, but here it's ok just to skip
            break
        }
    }
}
0 голосов
/ 04 января 2019

Нет необходимости реализовывать соответствие Hashable вручную, компилятор может автоматически синтезировать эти четыре ваших конкретных enum (где все случаи со связанными значениями имеют Hashable связанное значение). Вам просто нужно заявить о соответствии.

enum MyEnum: Hashable {
    case caseOne(Int)
    case caseTwo(String)
    case caseThree
}

// You don't even need to write `: Equatable`, since automatic Hashable conformance takes care of Equatable too, I just left it there for clarity
extension MyEnum: Equatable {
    static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
        switch (lhs, rhs) {
        case (.caseOne, .caseOne), (.caseTwo, .caseTwo), (.caseThree, .caseThree):
            return true
        default:
            return false
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...