在swift中索引并迭代CollectionType

时间:2016-02-18 01:45:38

标签: swift generics swift-protocols

我的代码基本上是这样的:

func arrayHalvesEqual(data:[UInt8]) -> Bool {
    let midPoint = data.count / 2
    for i in 0..<midPoint {
        let b = data[i]
        let b2 = data[i + midPoint]
        if b != b2 {
            return false
        }
    }
    return true
}

这样可以正常工作,但有时我想传入Arrays,有时则传入ArraySlice。我以为我将其更改为使用泛型和CollectionType协议,该协议转换如下:

func arrayHalvesEqual<ByteArray : CollectionType where ByteArray.Generator.Element == UInt8>(data:ByteArray) -> Bool {
    let midPoint = data.count / 2
    for i in 0..<midPoint {
        let b = data[i]
        let b2 = data[i + midPoint]
        if b != b2 {
            return false
        }
    }
    return true
}

但是,我收到以下编译器错误:

error: binary operator '..<' cannot be applied to operands of type 'Int' and 'ByteArray.Index.Distance'
    for i in 0..<midPoint {

我可以将for循环切换到for i in data.indices进行编译,但是我不能再将它除以2来获取midPoint,因为data.indices返回抽象CollectionType.Index而/ 2是一个Int。

在Swift中可以做这样的事吗?我可以在抽象协议索引类型和一些可以进行数学运算的实际类型之间架桥吗?

PS:我已经看过并发现了使用indicesenumerate迭代整个集合的其他示例,但我显然只想迭代一半的集合,这需要某种排序除以2

由于

1 个答案:

答案 0 :(得分:1)

您可以将方法限制为已编制索引的集合 Int

func arrayHalvesEqual<ByteArray : CollectionType where ByteArray.Index == Int, ByteArray.Generator.Element == UInt8>
    (data:ByteArray) -> Bool { ... }

这包括ArrayArraySlice

如果您使用indices.startIndex而不是0作为初始索引 那么将索引类型限制为IntegerType就足够了。 此外,数据类型UInt8可以替换为通用Equatable, 并且整个方法缩短为

func arrayHalvesEqual<ByteArray : CollectionType where ByteArray.Index : IntegerType, ByteArray.SubSequence.Generator.Element : Equatable>
    (data:ByteArray) -> Bool {

        let midPoint = (data.indices.endIndex - data.indices.startIndex)/2
        let firstHalf = data[data.indices.startIndex ..< midPoint]
        let secondHalf = data[midPoint ..< data.indices.endIndex]
        return !zip(firstHalf, secondHalf).contains { $0 != $1 }
}