从正常集合索引和反向集合索引创建范围
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 ""
}
}
或者,在您需要使用索引本身的情况下,您可以结合使用 Optional
的 map(_:)
方法和集合的 index(before:)
方法来获取索引之前:
let index = (buffer.reversed().index{ [=11=] != 0x20 }?.base).map{ buffer.index(before: [=11=]) }
(一个更大问题的简化示例。是的,我知道这个具体的简化示例可以用更简单的方法解决。)
我有一个包含一些 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 ""
}
}
或者,在您需要使用索引本身的情况下,您可以结合使用 Optional
的 map(_:)
方法和集合的 index(before:)
方法来获取索引之前:
let index = (buffer.reversed().index{ [=11=] != 0x20 }?.base).map{ buffer.index(before: [=11=]) }