Почему struct должна соответствовать Hashable, а также универсальному массиву при преобразовании в словарь - PullRequest
0 голосов
/ 08 января 2019

Целью было преобразовать элементы из общего списка в словарь для переменной uniqueKeys, но я увидел ошибку:

Невозможно указать значение неправильного или неоднозначного типа

Я знал что-то необходимое для соответствия протоколу Hashable и в итоге нашел решение, но не до конца понимаю, почему это решение работает.

  1. Я понимаю, почему T должно быть Hashable, поскольку оно входит в ключ словаря, но почему также CustomSet?
  2. Если CustomSet использует Hashable, почему мне не нужно ничего писать в его расширении?

исходный код

struct CustomSet<T : Comparable > {
    private var list: [T]
    init(_ list: [T]){
        let uniqueKeys = list.reduce(into: [:]){ dict, item in
            dict[item, default: 0] += 1
        }.keys
        self.list = Array(uniqueKeys)
    }
}

extension CustomSet : Equatable {
    static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
        return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
    }
}  

Я наконец решил это с помощью:

struct CustomSet<T : Comparable > : Hashable where T : Hashable {
    private var list: [T]
    init(_ list: [T]){
        let uniqueKeys = list.reduce(into: [:]){ dict, item in
            dict[item, default: 0] += 1
        }.keys
        self.list = Array(uniqueKeys)
    }
}

extension CustomSet : Equatable {
    static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
        return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
    }
}  

Я также заметил, что с учетом расширения: extension CustomSet: Hashable where T : Hashable не похоже на struct CustomSet<T : Comparable > : Hashable where T : Hashable с точки зрения добавления протокола Hashable, потому что я все еще вижу эту ошибку

Что я пробовал

Если я добавлю это к универсальному типу T, я все еще вижу ту же ошибку.

struct CustomSet<T : Comparable, Hashable >

Если я добавлю Hashable к CustomSet, я вижу ошибку

Невозможно преобразовать значение типа '[T]' в ожидаемый тип аргумента. 'UnsafeRawBufferPointer'

и

Наследование от недопустимого типа 'Hashable'

extension CustomSet : Equatable, Hashable {
    static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
        return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
    }

    func hash(into hasher: inout Hasher) {
       var hashValue: Int {
           var hasher = Hasher()
           self.hash(into: &hasher)
           return hasher.finalize()
       }
    }
 }

1 Ответ

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

Нет необходимости заставлять CustomSet соответствовать Hashable. Простое добавление ограничения Hashable к параметру универсального типа устраняет ошибку

Невозможно указать значение неправильного или неоднозначного типа

, что ожидается, поскольку ключи Dictionary должны соответствовать Hashable.

Кстати, синтаксис объявления соответствия нескольким протоколам &, а не ,, поэтому нет необходимости в предложении where.

struct CustomSet<T : Comparable & Hashable> {
    private var list: [T]
    init(_ list: [T]){
        let uniqueKeys = list.reduce(into: [:]){ dict, item in
            dict[item, default: 0] += 1
            }.keys
        self.list = Array(uniqueKeys)
    }
}

extension CustomSet : Equatable {
    static func == (lhs: CustomSet, rhs: CustomSet) -> Bool {
        return lhs.list.count == rhs.list.count && lhs.list.sorted() == rhs.list.sorted()
    }
}

Более того, вы можете просто сделать self.list = Array(Set(list)) в инициализаторе, чтобы сохранить только уникальные элементы из ввода в list, нет необходимости возиться с Dictionary.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...