【问题标题】:Pure swift set with protocol objects带有协议对象的纯 swift 集
【发布时间】:2015-03-26 12:37:19
【问题描述】:

有没有办法使以下内容真正起作用?

V1-“测试协议不符合Hashable”

protocol testProtocol  {
    //
}

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

V2 - "Protocol 'testProtocol' 只能用作通用约束,因为它具有 Self 或关联的类型要求

protocol testProtocol : Hashable {
    //
}

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

我假设答案是否定的——因为协议(即使带有@objc 标签)没有足够的信息?但也许我在这里缺少某种线或东西。

【问题讨论】:

    标签: swift set protocols


    【解决方案1】:

    一种解决方案是将集合包装在一个类或结构中,并约束插入函数,使其仅接受符合您的协议可散列的项目。然后,您可以在实现中使用 SetAnyHashable

    例如:

    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()
        }
    }
    

    通过对插入函数施加约束,您是在说“这个集合必须包含符合协议且可散列的东西”,而实际上并未将协议限制为可散列。

    如果包装集类本身可以是通用的,并且接受要遵守的协议,那就更好了,但我还没有弄清楚这是否可能!

    【讨论】:

    • 谢谢!!!它真的帮助了我。我只是不强迫铸造(项目为!MyProtocol)。干杯
    • 很好的答案@Sam Deane。 @Jeef 这真的应该是公认的答案。当前接受的答案强制您使用特定类进行初始化,而不是允许所有符合 testProtocol 的异构对象。
    【解决方案2】:

    也许有更好的解决方案,但你可以让你的类通用:

    protocol testProtocol : Hashable {
        //
    }
    
    class test<P: testProtocol> {
        var s : Set<P>?
    
        init() { }
    }
    

    【讨论】:

    • 但这意味着您的集合的对象都需要共享一个类(或超类),这意味着您添加了另一个要求。这是否意味着您不能在 Swift 中为受协议一致性约束的事物创建Set
    • @Zack:问题在于 Hashable 继承自 Equatable 协议,该协议具有“自我要求”,在本例中为运算符 func ==(lhs: Self, rhs: Self) -&gt; Bool
    • 是的,我知道这一点。虽然我个人认为在 2.0 的语言设计中让Equatable 要求您要比较的两个项目具有相同的类层次结构是一个错误。我已经在 Apple 的 Swift 开发者论坛上问过这个问题,希望他们能提出建议,而不是分叉 EquatableHashableSet 以允许比较不同类层次结构的项目。
    • @Zack:我无法判断这是否是一个好的设计决策。不妨看看“面向协议的 Swift 编程”WWDC 会议视频,其中解释了这背后的基本原理。
    • 我实际上在房间里参加那个会议:D
    【解决方案3】:

    我知道这不是Set(就像所要求的问题一样),但您可以使用NSHashTable 而不是Set。不过,您必须将您的协议公开给 objc。虽然不是Set,但如果您只是想存储协议对象的集合而不必符合Hashable,这将起作用:

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

    这样您就可以使用提供的addremove 函数。

    此外,如果您要存储观察者或类似的东西,您可以使用NSHashTable.weakObjects() 初始化哈希表,这将确保不会保留对象。

    这里有更多关于NSHashTablehttps://developer.apple.com/documentation/foundation/nshashtable

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2015-04-02
      • 1970-01-01
      • 2017-04-27
      • 2014-09-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多