为什么我的Swift协议扩展无法包装相同类型的现有函数?

时间:2016-12-08 16:46:07

标签: swift swift-protocols

我试图创造一个安全的"集合的下标运算符 - 忽略超出集合的可用索引的部分范围的运算符。

所需的行为是在所有情况下都返回一个Slice;当下标范围和收集范围之间没有重叠时,应该返回空数组。

这似乎是对this answer中提出的技术的直接扩展。 documentation of the collection subscript operator is very straightforward

subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }

但是当我在我的包装函数中采用相同的类型时,我会得到以下结果: snippet

复制/粘贴版本:

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>(在文档中指定)但仍然认为它是错误的?

1 个答案:

答案 0 :(得分:4)

The ranged subscript requirement of Collection返回SubSequence(关联类型):

subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get }

subscript that you refer to

subscript(bounds: Range<Self.Index>) -> Slice<Self> { get }

只是该下标的默认实现,其中SubSequenceSlice<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]
    }
}