SubSequence指数的兼容性

时间:2016-10-23 11:58:36

标签: swift string generics collections

对于大多数Swift CollectionsCollection's SubSequence的索引与基座Collection兼容。

func foo<T: Collection>(_ buffer: T) -> T.Iterator.Element
    where T.Index == T.SubSequence.Index
{
    let start = buffer.index(buffer.startIndex, offsetBy: 2)
    let end = buffer.index(buffer.startIndex, offsetBy: 3)
    let sub = buffer[start ... end]
    return buffer[sub.startIndex]
}

这适用于大多数集合:

print(foo([0, 1, 2, 3, 4])) // 2

即使是String.UTF8View

print(foo("01234".utf8) - 0x30 /* ASCII 0 */) // 2

但是当使用String.CharacterView时,事情就开始破坏了:

print(foo("01234".characters)) // "0"

对于CharacterView,SubSequences创建完全独立的实例,即Index再次从0开始。要转换回主String索引,必须使用distance函数并将其添加到startIndexSubSequenceString的内容。

func foo<T: Collection>(_ buffer: T) -> T.Iterator.Element
    where T.Index == T.SubSequence.Index, T.SubSequence: Collection, T.SubSequence.IndexDistance == T.IndexDistance
{
    let start = buffer.index(buffer.startIndex, offsetBy: 2)
    let end = buffer.index(buffer.startIndex, offsetBy: 3)
    let sub = buffer[start ... end]

    let subIndex = sub.startIndex
    let distance = sub.distance(from: sub.startIndex, to: subIndex)
    let bufferIndex = buffer.index(start, offsetBy: distance)
    return buffer[bufferIndex]
}

有了这个,现在所有三个例子都正确打印2。

  • 为什么String SubSequence索引与其基本字符串不兼容?只要一切都是不可变的,对我来说,为什么Strings是一个特例,即使有所有Unicode的东西也没有意义。我还注意到,substring函数返回字符串而不像大多数其他集合那样返回Slices。但是,子字符串仍然记录为在O(1)中返回。奇怪的魔法。

  • 有没有办法约束泛型函数以限制SubSequence索引与基本序列兼容的集合?

  • 甚至可以假设SubSequence索引与非String集合兼容,或者这只是巧合,应该始终使用distance(from:to:)来转换索引吗?

1 个答案:

答案 0 :(得分:1)

那是discussed on swift-evolution,作为错误报告提交 SR-1927 – Subsequences of String Views don’t behave correctly最近修复了 在StringCharacterView.swiftcommit

使用该修复String.CharacterView的行为 与其他集合一样,其切片应使用与原始集合相同元素的相同索引。