Swift:任何类型的序列作为函数参数

时间:2016-05-26 10:49:06

标签: swift swift2 sequence

我创建了自定义序列类型,我希望函数接受任何类型的序列作为参数。 (我想使用两个集合,以及我的序列类型)

这样的事情:

private func _addToCurrentTileset(tilesToAdd tiles: SequenceType)

我有什么方法可以做到吗?

看起来相对简单,但我无法以某种方式解决这个问题。 Swift工具链告诉我: Protocol 'SequenceType' can only be used as a generic constraint because it has Self or associated type requirements,我不知道如何创建一个符合SequenceType和Self要求的协议。

我可以消除associatedType要求,但不能消除Self:

protocol EnumerableTileSequence: SequenceType {
    associatedtype GeneratorType = geoBingAnCore.Generator
    associatedtype SubSequence: SequenceType = EnumerableTileSequence
}

现在如果说我可以消除自我要求,那么已经使用这样的协议定义其他collectionType实体,如数组,集合将不符合它。

参考: 我的自定义序列是枚举器类型的所有子类,定义为:

public class Enumerator<T> {

    public func nextObject() -> T? {
        RequiresConcreteImplementation()
    }
}

extension Enumerator {

    public var allObjects: [T] {
        return Array(self)
    }
}

extension Enumerator: SequenceType {

    public func generate() -> Generator<T> {
        return Generator(enumerator: self)
    }
}

public struct Generator<T>: GeneratorType {

    let enumerator: Enumerator<T>
    public mutating func next() -> T? {
        return enumerator.nextObject()
    }
} 

2 个答案:

答案 0 :(得分:12)

编译器告诉你答案:“协议'序列'只能用作作为通用约束,因为它具有自我或相关类型要求”。

因此,您可以使用泛型来执行此操作:

private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T) {
    ...
}

这将允许您将符合Sequence的任何具体类型传入您的函数。 Swift将推断具体类型,允许您在不丢失类型信息的情况下传递序列。

如果要将序列中元素的类型限制为给定协议,可以执行以下操作:

private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T)  where T.Element: SomeProtocol {
    ...
}

或具体类型:

private func _addToCurrentTileset<T: Sequence>(tilesToAdd tiles: T)  where T.Element == SomeConcreteType {
    ...
}

如果您不关心序列本身的具体类型(对于将它们混合在一起并且在大多数情况下存储它们很有用),那么Anton's answer可以让您了解类型擦除版本的{{ 1}}。

答案 1 :(得分:4)

您可以使用type-eraser AnySequence

  

类型擦除序列。

     

将操作转发到具有相同Element类型的任意基础序列,隐藏基础SequenceType的具体内容。

E.g。如果您需要将瓷砖存储为内部属性或以某种方式在对象的结构中使用其具体类型,那么这将是最佳选择。

如果你只需要能够使用不必存储它的序列(例如只有map),那么你可以简单地使用泛型(比如@ originaluser2建议)。例如。你最终会得到类似的东西:

private func _addToCurrentTileset<S: SequenceType where S.Generator.Element == Tile>(tilesToAdd tiles: S) {
    let typeErasedSequence = AnySequence(tiles) // Type == AnySequence<Tile>
    let originalSequence = tiles // Type == whatever type that conforms to SequenceType and has Tile as its Generator.Element
}