Swift: Any Kind 序列作为函数参数

Swift: Any Kind of sequence as a function parameter

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

像这样:

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

你可以使用类型橡皮擦AnySequence

A type-erased sequence.

Forwards operations to an arbitrary underlying sequence having the same Element type, hiding the specifics of the underlying SequenceType.

例如如果您需要将图块存储为内部 属性 或以某种方式在您的对象结构中使用其具体类型,那么这就是方法。

如果您只需要能够使用必须存储它的序列 w/o(例如仅 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
}

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

因此您可以使用泛型来做到这一点:

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 {
    ...
}

如果您不关心序列本身的具体类型(对于将它们混合在一起以及在大多数情况下存储它们很有用),那么 已经为您提供了类型擦除版本Sequence.