在 swift 中对 CollectionType 进行索引和迭代

Index and Iterate over CollectionType in swift

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

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 来得到中点,因为 data.indices returns 抽象CollectionType.Index 而 / 2 是一个整数。

是否可以在 Swift 中做这样的事情?我可以在抽象协议索引类型和我可以做数学运算的真实类型之间建立桥梁吗?

P.S:我已经看到并找到了使用 indicesenumerate 迭代整个集合的其他示例,但我明确只想迭代一半的集合这需要除以 2

谢谢

您可以将方法限制为索引的集合 通过 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 { [=11=] !=  }
}