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

时间:2016-10-22 11:39:42

标签: swift generics collections reverse

(一个更大问题的简化示例。是的,我知道这个特别愚蠢的例子可以用更简单的方式解决。)

我有一个包含一些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: { $0 != 0x20 /* SP */ }),
       let valueEnd = buffer.reversed().index(where: { $0 != 0x20 /* SP */ })
    {
        return String(bytes: buffer[valueStart ... valueEnd], encoding: .utf8)!
    } else {
        return ""
    }
}

然而,我收到此错误:

  

错误:二元运算符&#39; ...&#39;不能应用于类型&#39; T.Index&#39;的操作数。和&#39; ReversedIndex&#39;

BidirectionalCollection州的文件:

  

如果您需要相同类型的反向集合,您可以使用集合的基于序列或基于集合的初始化程序。

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

  

错误:&#39; T&#39;无法构造,因为它没有可访问的初始值设定项

因为,显然,初始化器是在其他地方定义的。

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

我在这里俯瞰什么?

1 个答案:

答案 0 :(得分:1)

为了从ReversedIndex获取基础集合的索引,您只需使用其base属性。

虽然注意到由于ReversedCollection is implemented的方式,这实际上会返回基本集合中给定索引的上面的索引(因为startIndex是映射到endIndex - 这是一个超过结束&#39;索引)。

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

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: {$0 != 0x20}),
        let valueEnd = buffer.reversed().index(where: {$0 != 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 ""
    }
}

或者,如果您需要使用索引本身,可以将Optional&n; map(_:)方法与集合index(before:)结合使用获取索引的方法:

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