【问题标题】:Swift: Any Kind of sequence as a function parameterSwift:任何类型的序列作为函数参数
【发布时间】:2016-09-24 07:53:19
【问题描述】:

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

类似这样的:

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 要求的协议。

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

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

【问题讨论】:

    标签: swift swift2 sequence


    【解决方案1】:

    编译器会告诉你答案:“协议‘序列’只能用作通用约束,因为它有 Self 或关联的类型要求”。 p>

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

    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 已经为您提供了Sequence 的类型擦除版本。

    【讨论】:

    • 非常感谢,我其实很关心序列里面元素的类型,有什么办法可以限制里面的元素类型吗?类似于:
    • @ambientlight 当然,如果TileID 是协议,您可以使用&lt;T:SequenceType where T.Generator.Element:TileID&gt;,如果是具体类型,则可以使用== TileID
    【解决方案2】:

    您可以为此使用 type-eraser AnySequence

    类型擦除的序列。

    将操作转发到具有相同Element 类型的任意底层序列,隐藏底层SequenceType 的细节。

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

    如果您只需要能够使用序列而无需存储它(例如,只需 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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多