【发布时间】:2017-04-23 23:57:43
【问题描述】:
我正在尝试为集合创建一个“安全”的下标运算符——它忽略超出集合可用索引的范围部分。
期望的行为是在所有情况下都返回一个 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]
}
}
为什么我不能以这种方式下标集合?为什么编译器确认我使用了正确类型的 Range<Self.Index>(在文档中指定)但仍然认为这是一个错误?
【问题讨论】:
-
请注意,您的
where Indices.Iterator.Element == Index约束未在您的自定义下标中使用。您可能需要考虑将其移动到Collection的无约束扩展中(假设您有其他方法使用当前方法中的约束)。 -
更简单地说,Hamish 的回答是:
self[lo..<hi]是Self.SubSequence,所以你不能在预期Slice<Self>的地方返回它。当然,错误消息(通常如此)非常具有误导性。 -
@Hamish 我认为我的扩展中的其他功能需要该约束(the one in this answer),但即便如此——根据我在那里的评论——我不明白它的构造
-
@Ian 有趣的是,我在this answer 中建议了该约束,您链接到的答案提到了该约束。您可以在该答案中看到
Indices的定义,并且您可以看到它没有承诺其元素的类型(因此编译器无法知道它们是否为Equatable,因此您是否可以在.indices上使用contains(_:)方法)。 -
但是,一旦在关联类型上允许使用
where子句,我希望 stdlib 团队在Indices中添加一个,将其Iterator.Element限制为Index类型(因为这就是它是索引的集合),这将允许您取消扩展约束。在那之前,我在第一条评论中的建议是对范围下标使用Collection的一个无约束扩展,然后对Collection进行另一个扩展,这次使用where Indices.Iterator.Element == Index作为单个索引下标。
标签: swift swift-protocols