2015-10-17 108 views
12

我想用Hashable协议和自定义协议对应的值初始化Set。在Swift中设置和协议

我想:

protocol CustomProtocol: Hashable {} 

let set = Set<CustomProtocol>() 

但Xcode的抱怨:

使用 'CustomProtocol' 作为具体类型符合协议 '哈希的' 不支持

如何我做到了吗?

在此先感谢。

+0

已经需要符合Hashable的对象。 – Abizern

+0

如果CustomProtocol不符合Hashable,则Xcode会抱怨CustomProtocol不符合它。看起来我错过了一些东西。 –

回答

8

为什么你不能做你想做的事情的直接原因是Hashable是一个通用的协议。因此它或者从它派生的协议不能用作Set的元素类型。泛型类型只能用作另一个泛型中的约束。你会注意到,即使一个集合的元素类型必须符合到Hashable,你也不能声明Set<Hashable>

最简单的方法是,不是一组协议,而是一组对象类型。例如,如果S是符合CustomProtocol(因为它符合哈希的加任何其他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的集合。

+0

谢谢。但我想从不同的类插入我的集合对象,而不是一个。这就是为什么我不想创建一套“协议集”。 –

+0

看到我修改后的答案。 – matt

+0

当然,最简单的方法就是让你的所有类都从NSObject派生出来,正如你已经被建议的那样。 – matt

1

在Swift 3中,一种解决方案是使用AnyHashable structure

例如,创建一个观察员/可观察的模式,我们可以这样做:

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

请注意,我从我的协议Observer分开Hashable协议。