【发布时间】:2016-10-23 11:58:36
【问题描述】:
对于大多数 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 创建完全独立的实例,即索引从 0 重新开始。要转换回主字符串索引,必须使用 distance 函数并将其添加到 @987654335 的 startIndex @在主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。
为什么字符串子序列索引与其基本字符串不兼容?只要一切都是不可变的,对我来说为什么字符串是一个特例是没有意义的,即使是所有 Unicode 的东西。我还注意到子字符串函数返回字符串而不是像大多数其他集合那样返回切片。但是,仍然记录子字符串在 O(1) 中返回。奇怪的魔法。
有没有办法约束泛型函数以限制子序列索引与基本序列兼容的集合?
是否可以假设 SubSequence 索引与非字符串集合兼容,或者这只是巧合,应该始终使用
distance(from:to:)来转换索引?
【问题讨论】:
-
这已在 Swift 邮件列表中进行了讨论,并且有一个针对角色视图或集合的一般性修复该问题的建议。我看看能不能找到链接。
-
“修复”是指调整 CharacterView 以匹配常规 Collections,还是调整 Collection 索引使其不再兼容 SubSequences 和 Base Sequences?
-
这里是错误报告bugs.swift.org/browse/SR-1927,这里是修复它的拉取请求github.com/apple/swift/pull/4896。
-
谢谢!如果您重新提交此评论作为答案,我会接受它:)
标签: swift string generics collections