我试图创造一个安全的"集合的下标运算符 - 忽略超出集合的可用索引的部分范围的运算符。
所需的行为是在所有情况下都返回一个Slice;当下标范围和收集范围之间没有重叠时,应该返回空数组。
这似乎是对this answer中提出的技术的直接扩展。 documentation of the collection subscript operator is very straightforward:
subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }
但是当我在我的包装函数中采用相同的类型时,我会得到以下结果:
复制/粘贴版本:
extension Collection where Indices.Iterator.Element == Index {
subscript(safe bounds: Range<Self.Index>) -> Slice<Self> {
let empty = Slice(base: self, bounds: (startIndex..<startIndex))
guard bounds.lowerBound < endIndex else { return empty }
guard bounds.upperBound >= startIndex else { return empty }
let lo = Swift.max(startIndex, bounds.lowerBound)
let hi = Swift.min(endIndex, bounds.upperBound)
return self[lo..<hi]
}
}
为什么我不能以这种方式下标Collection?为什么编译器确认我使用了正确类型的Range<Self.Index>
(在文档中指定)但仍然认为它是错误的?
答案 0 :(得分:4)
The ranged subscript requirement of Collection
返回SubSequence
(关联类型):
subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get }
subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }
只是该下标的默认实现,其中SubSequence
是Slice<Self>
。符合Collection
的任何类型都可以以不同方式实现此要求 - 他们无需将SubSequence
定义为Slice<Self>
。
因此,您只需更改扩展程序即可反映您使用的下标中返回SubSequence
:
extension Collection {
subscript(safe bounds: Range<Index>) -> SubSequence {
// as the method returns a SubSequence,
// use the regular subscript to get an empty SubSequence
let empty = self[startIndex..<startIndex]
guard bounds.lowerBound < endIndex else { return empty }
guard bounds.upperBound >= startIndex else { return empty }
let lo = Swift.max(startIndex, bounds.lowerBound)
let hi = Swift.min(endIndex, bounds.upperBound)
return self[lo..<hi]
}
}