(一个更大问题的简化示例。是的,我知道这个特别愚蠢的例子可以用更简单的方式解决。)
我有一个包含一些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;
如果您需要相同类型的反向集合,您可以使用集合的基于序列或基于集合的初始化程序。
但是,当我尝试在buffer.reversed()
中嵌入T()
时,我收到此错误:
错误:&#39; T&#39;无法构造,因为它没有可访问的初始值设定项
因为,显然,初始化器是在其他地方定义的。
最后,我不需要整个反向收集属于某种类型。我只想从原始集合的索引和相应的反向集合索引中构建范围。
我在这里俯瞰什么?
答案 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) }