对于大多数Swift Collections
,Collection'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
函数并将其添加到startIndex
主SubSequence
中String
的内容。
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:)
来转换索引吗?
答案 0 :(得分:1)
那是discussed on swift-evolution,作为错误报告提交 SR-1927 – Subsequences of String Views don’t behave correctly最近修复了 在StringCharacterView.swift 同 commit
使用该修复String.CharacterView
的行为
与其他集合一样,其切片应使用与原始集合相同元素的相同索引。