Набор и протоколы в Swift

Я хотел бы инициализировать Set со значениями, соответствующими протоколу Hashable и настраиваемому протоколу.

Я пробовал:

protocol CustomProtocol: Hashable {}

let set = Set<CustomProtocol>()

Но Xcode жалуется:

Использование "CustomProtocol" в качестве конкретного типа, соответствующего протоколу "Hashable" не поддерживается

Как я могу это достичь?

Спасибо заранее.

Ответ 1

Непосредственная причина, по которой вы не можете делать то, что вы хотите сделать, это то, что Hashable является общим протоколом. Таким образом, он - или протокол, который вытекает из него, - не может использоваться в качестве типа элемента Set. Общий тип может использоваться только как ограничение в другом родовом значении. Вы заметите, что вы не можете объявить Set<Hashable>, даже если тип элемента набора должен соответствовать Hashable.

Самый простой способ - это не набор протоколов, а набор некоторых типов объектов. Например, если S - это структура, которая соответствует CustomProtocol (поскольку она соответствует Hashable плюс все, что связано с CustomProtocol), вы можете объявить набор S.

Пример:

protocol CustomProtocol: Hashable {

}

func ==(lhs:S,rhs:S) -> Bool {
    return lhs.name == rhs.name
}

struct S : CustomProtocol {
    var name : String
    var hashValue : Int { return name.hashValue }
}

let set = Set<S>()

Если проблема, которую вы пытаетесь решить, состоит в том, что вам нужен набор смешанных типов, которые, тем не менее, равнозначны друг другу, то это та самая проблема, которая решена с помощью расширений протокола, что объясняется обсуждением в видео на основе протокола WWDC 2015.

Но было бы проще просто сделать все классы типов, которые получаются из NSObject. Вы все же можете заставить их принять какой-то вторичный протокол, конечно, но набор не будет определен как набор этого протокола, а NSObject.

Ответ 2

В Swift 3 одним из решений является использование AnyHashable structure.

Например, чтобы создать шаблон Observers/Observable, мы могли бы сделать:

protocol Observer {
    func observableDidSomething(_ observable: Observable)
}

class Observable {
    private var observersSet: Set<AnyHashable> = []

    private var observers: [Observer] {
        return observersSet.flatMap { $0 as? Observer }
    }

    func add<O>(_ observer: O) where O : Observer, O : Hashable {
        observersSet.insert(observer)
    }

    func remove<O>(_ observer: O) where O : Observer, O : Hashable {
        observersSet.remove(observer)
    }

    // ...

    private func doSomething() {
        // do something ...
        observers.forEach { $0.observableDidSomething(self) }
    }
} 

Обратите внимание, что я отделяю протокол Hashable от моего протокола Observer.