Чистый быстрый набор с объектами протокола

Есть ли способ сделать следующее на самом деле работать?

V1 - "протокол испытаний не соответствует Hashable"

protocol testProtocol  {
    //
}

class test {
    var s : Set<testProtocol>?
    init(){
    }
}

V2 - "Протокол" testProtocol "может использоваться только в качестве общего ограничения, поскольку он имеет собственные или связанные требования типа

protocol testProtocol : Hashable {
    //
}

class test {
    var s : Set<testProtocol>?
    init(){
    }
}

Я предполагаю, что ответа нет, потому что протоколы (даже с тегом @objc) не имеют достаточной информации? но, может быть, есть какая-то строка или вещь, которую я здесь отсутствует.

Ответ 1

Возможно, есть лучшее решение, но вы можете сделать свой класс общим:

protocol testProtocol : Hashable {
    //
}

class test<P: testProtocol> {
    var s : Set<P>?

    init() { }
}

Ответ 2

Одно из решений состоит в том, чтобы обернуть набор в класс или структуру и ограничить функцию вставки так, чтобы она принимала только те элементы, которые соответствуют вашему протоколу и допускают хэширование. Затем вы можете использовать Set AnyHashable в реализации.

Например:

protocol MyProtocol {
    func doStuff()
}

class MyProtocolSet {
    var set = Set<AnyHashable>()

    func insert<T>(_ item: T) where T: MyProtocol, T: Hashable {
        set.insert(AnyHashable(item))
    }

    func iterate( doing: (MyProtocol) -> Void ) {
        for item in set {
            doing(item as! MyProtocol)
        }
    }
}

struct Foo: MyProtocol, Hashable {
    func doStuff() { print("foo") }
}

struct Bar: MyProtocol, Hashable {
    func doStuff() { print("bar") }
}

func test() {
    let set = MyProtocolSet()
    set.insert(Foo())
    set.insert(Bar())
    set.iterate { (item: MyProtocol) in
        item.doStuff()
    }
}

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

Было бы еще лучше, если бы класс оберточного набора сам по себе был бы универсальным и принимал протокол для соответствия, но я пока не выяснил, возможно ли это!

Ответ 3

Я знаю, что это не Set (как и заданный вопрос), но вы можете использовать NSHashTable вместо Set. Вы должны будете выставить свой протокол на objc. Хотя это и не Set, если вы просто хотите сохранить коллекцию объектов протокола без необходимости соответствовать Hashable, это будет работать:

@objc protocol testProtocol { }
class Object {
    var s: NSHashTable<testProtocol>!
}

Таким образом, вы можете использовать предоставляемые функции add и remove.

Кроме того, если вы храните наблюдатели или что-то подобное, вы можете инициализировать хеш-таблицу с помощью NSHashTable.weakObjects(), которая обеспечит сохранение объектов.

Вот больше о NSHashTable: https://developer.apple.com/documentation/foundation/nshashtable