2015-10-17 136 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協議。