在Swift 3中,我希望能够创建一个协议,允许我添加元素并使用for element in进行迭代。该协议应该同时适用于NSMutableSet和NSMutableOrderedSet (因为它们不是从同一个类继承的)。
我知道NSMutableSet和NSMutableOrderedSet不继承同一个类有很好的理由,解释了这里和这里。
但是我想创建一个协议,它只使用NSMutableSet (和NSMutableOrderedSet)中所有方法的一小部分。
我让add开始工作了,就像这样:
protocol MutableSet {
func add(_ element: Any)
}
extension NSMutableSet: MutableSet {}
extension NSMutableOrderedSet: MutableSet {}
let one: NSString = "one"
let two: NSString = "two"
// Works if created with `NSMutableSet`
let mutableSet: MutableSet = NSMutableSet()
mutableSet.add(one)
mutableSet.add(two)
for element in mutableSet as! NSMutableSet {
print(element)
}
/*
This prints:
one
two
*/
// Also works if creating `NSMutableOrderedSet` instance
let mutableOrderedSet: MutableSet = NSMutableOrderedSet()
mutableOrderedSet.add(one)
mutableOrderedSet.add(two)
for element in mutableOrderedSet as! NSMutableOrderedSet {
print(element)
}
/*
This prints:
one
two
*/但是,我非常希望能够通过以下方法来迭代这些元素:
for element in mutableSet {
print(element)
}我试图使protocol MutableSet符合Sequence协议,类似于这样,但它不起作用:
protocol MutableSet: Sequence {
func add(_ element: Any)
}
extension NSMutableSet: MutableSet {
typealias Iterator = NSFastEnumerationIterator
typealias Element = NSObject // I dont know what to write here
typealias SubSequence = Slice<Set<NSObject>> // Neither here....
}
let one: NSString = "one"
let two: NSString = "two"
let mutableSet: MutableSet = NSMutableSet() // Compile Error: Protocol `MutableSet` can only be used as a generic constraint because it has Self or associated type requirements
mutableSet.add(one)
mutableSet.add(two)
for element in mutableSet { // Compile Error: Using `MutableSet` as a concrete type conforming to protocol `Sequence` is not supported
print(element)
}是否有可能使我的协议符合Sequence?我怎么发动汽车呢?我尝试过typealias和associatedtype of Element,Iterator等多种组合,我也尝试过这个答案 --它对我不起作用。
编辑2:在编辑1中回答我自己的问题
我让var count: Int { get }使用这个解决方案,但不确定它是否是最好的.如果不用在var elements: [Any] { get }和NSMutableOrderedSet,的扩展中实现,那也不错,但我想这是不可避免的?。
protocol MutableSet: Sequence {
subscript(position: Int) -> Any { get }
func add(_ element: Any)
var count: Int { get }
var elements: [Any] { get }
}
extension MutableSet {
subscript(position: Int) -> Any {
return elements[position]
}
}
extension NSMutableSet: MutableSet {
var elements: [Any] {
return allObjects
}
}
extension NSMutableOrderedSet: MutableSet {
var elements: [Any] {
return array
}
}
struct AnyMutableSet<Element>: MutableSet {
private let _add: (Any) -> ()
private let _makeIterator: () -> AnyIterator<Element>
private var _getElements: () -> [Any]
private var _getCount: () -> Int
func add(_ element: Any) { _add(element) }
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
var count: Int { return _getCount() }
var elements: [Any] { return _getElements() }
init<MS: MutableSet>(_ ms: MS) where MS.Iterator.Element == Element {
_add = ms.add
_makeIterator = { AnyIterator(ms.makeIterator()) }
_getElements = { ms.elements }
_getCount = { ms.count }
}
}
let one: NSString = "one"
let two: NSString = "two"
let mutableSet: AnyMutableSet<Any>
let someCondition = true
if someCondition {
mutableSet = AnyMutableSet(NSMutableSet())
} else {
mutableSet = AnyMutableSet(NSMutableOrderedSet())
}
mutableSet.add(one)
mutableSet.add(two)
for i in 0..<mutableSet.count {
print("Element[\(i)] == \(mutableSet[i])")
}
// Prints:
// Element[0] == one
// Element[1] == two编辑1:使用@rob-napier的优秀答案跟踪问题,使用type erasure技术,我扩展了protocol MutableSet,使其具有count和subscript能力,但是我只能使用丑陋的func (命名为getCount),而不是var。这就是我所用的:
protocol MutableSet: Sequence {
subscript(position: Int) -> Any { get }
func getCount() -> Int
func add(_ element: Any)
func getElements() -> [Any]
}
extension MutableSet {
subscript(position: Int) -> Any {
return getElements()[position]
}
}
extension NSMutableSet: MutableSet {
func getCount() -> Int {
return count
}
func getElements() -> [Any] {
return allObjects
}
}
extension NSMutableOrderedSet: MutableSet {
func getElements() -> [Any] {
return array
}
func getCount() -> Int {
return count
}
}
struct AnyMutableSet<Element>: MutableSet {
private var _getCount: () -> Int
private var _getElements: () -> [Any]
private let _add: (Any) -> ()
private let _makeIterator: () -> AnyIterator<Element>
func getElements() -> [Any] { return _getElements() }
func add(_ element: Any) { _add(element) }
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
func getCount() -> Int { return _getCount() }
init<MS: MutableSet>(_ ms: MS) where MS.Iterator.Element == Element {
_add = ms.add
_makeIterator = { AnyIterator(ms.makeIterator()) }
_getElements = ms.getElements
_getCount = ms.getCount
}
}
let one: NSString = "one"
let two: NSString = "two"
let mutableSet: AnyMutableSet<Any>
let someCondition = true
if someCondition {
mutableSet = AnyMutableSet(NSMutableSet())
} else {
mutableSet = AnyMutableSet(NSMutableOrderedSet())
}
mutableSet.add(one)
mutableSet.add(two)
for i in 0..<mutableSet.getCount() {
print("Element[\(i)] == \(mutableSet[i])")
}
// Prints:
// Element[0] == one
// Element[1] == two如何使它在协议中只与var count: Int { get } var elements: [Any] 和var elements: [Any]一起工作,而不是与函数一起工作?
发布于 2016-09-20 15:05:47
几乎每一个“我如何使用PAT (具有关联类型的协议).”的答案就是“放进盒子里”那个盒子是类型橡皮擦。在您的情况下,您需要一个AnyMutableSet。
import Foundation
// Start with your protocol
protocol MutableSet: Sequence {
func add(_ element: Any)
}
// Now say that NSMutableSet is one. There is no step two here. Everything can be inferred.
extension NSMutableSet: MutableSet {}
// Create a type eraser for MutableSet. Note that I've gone ahead and made it generic.
// You could lock it down to just Any, but why limit yourself
struct AnyMutableSet<Element>: MutableSet {
private let _add: (Any) -> ()
func add(_ element: Any) { _add(element) }
private let _makeIterator: () -> AnyIterator<Element>
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
init<MS: MutableSet>(_ ms: MS) where MS.Iterator.Element == Element {
_add = ms.add
_makeIterator = { AnyIterator(ms.makeIterator()) }
}
}
// Now we can use it
let one: NSString = "one"
let two: NSString = "two"
// Wrap it in an AnyMutableSet
let mutableSet = AnyMutableSet(NSMutableSet())
mutableSet.add(one)
mutableSet.add(two)
for element in mutableSet {
print(element)
}原则上还有另一种方法,就是直接使用现有的“协议”,该协议允许我添加元素并遍历使用for元素In。这是两个协议:SetAlgebra & Sequence。在实践中,我发现让NSMutableSet或NSOrderedSet符合SetAlgebra到be....annoying。NSMutableSet基本上是在Swift 3中被打破的,它在不同的地方都接受Any,但被定义为在AnyHashable之上。基本代码不工作:
let s = NSMutableSet()
let t = NSMutableSet()
s.union(t)但那是因为你不应该使用NSMutableSet。它将自动桥接到Set,您应该使用Set。Set和SetAlgebra & Sequence是一致的,所以这是很好的。
然后我们来到了NSOrderedSet。这很难连接到Swift (这就是为什么基金会团队已经推迟了这么长时间)。它真的是一种杂乱无章的类型,每次我尝试使用它时,我都会把它拔出来,因为它对任何东西都没有很好的发挥。(尝试使用NSFetchedResultsController在“有序关系”中使用订单。)坦率地说,最好的办法是将其封装在一个结构中,并使该结构符合SetAlgebra & Sequence。
但是,如果你不这样做(或者像我最终做的那样,去掉有序的集合),那么类型擦除几乎是你唯一的工具。
https://stackoverflow.com/questions/39593295
复制相似问题