从正常集合索引和反向集合索引创建范围

Creating range from normal collection index and reversed collection index

(一个更大问题的简化示例。是的,我知道这个具体的简化示例可以用更简单的方法解决。)

我有一个包含一些 ASCII 代码点的集合,我想删除其中的前导和尾随空格。

func foo<T: BidirectionalCollection>(_ buffer: T) -> String
    where T.Iterator.Element == UInt8,
          T.SubSequence.Iterator.Element == T.Iterator.Element
{
    if let valueStart = buffer.index(where: { [=10=] != 0x20 /* SP */ }),
       let valueEnd = buffer.reversed().index(where: { [=10=] != 0x20 /* SP */ })
    {
        return String(bytes: buffer[valueStart ... valueEnd], encoding: .utf8)!
    } else {
        return ""
    }
}

但是,我得到这个错误:

error: binary operator '...' cannot be applied to operands of type 'T.Index' and 'ReversedIndex'

BidirectionalCollection 的文档指出:

If you need a reversed collection of the same type, you may be able to use the collection's sequence-based or collection-based initializer.

但是,当我尝试将 buffer.reversed() 嵌入到 T() 中时,出现此错误:

error: 'T' cannot be constructed because it has no accessible initializers

因为显然初始化器是在别处定义的。

最后,我不需要整个反向集合都是某种类型。我只想能够从原始集合的索引和相应的反向集合的索引构建范围。

我在这里忽略了什么?

为了从 ReversedIndex 获取基础集合的索引,您可以简单地使用其 base 属性.

虽然请注意,由于 ReversedCollection is implemented 的方式,这实际上 return 索引 高于 基中给定的索引集合(因为 startIndex 映射到 endIndex – 这是一个 'past the end' 索引)。

因此,您可以简单地使用半开范围运算符 ..< 以使该索引成为非包含上限:

func foo<T: BidirectionalCollection>(_ buffer: T) -> String
    where T.Iterator.Element == UInt8,
    T.SubSequence.Iterator.Element == T.Iterator.Element
{
    if let valueStart = buffer.index(where: {[=10=] != 0x20}),
        let valueEnd = buffer.reversed().index(where: {[=10=] != 0x20})?.base
    {
        // goes without saying that this will crash if String(bytes:encoding:) returns nil.
        return String(bytes: buffer[valueStart ..< valueEnd], encoding: .utf8)!
    } else {
        return ""
    }
}

或者,在您需要使用索引本身的情况下,您可以结合使用 Optionalmap(_:) 方法和集合的 index(before:) 方法来获取索引之前:

let index = (buffer.reversed().index{ [=11=] != 0x20 }?.base).map{ buffer.index(before: [=11=]) }