问题:
当试图跨过去时String.CharacterView.Index
索引,例如一步2
extension String.CharacterView.Index : Strideable { }
let str = "01234"
for _ in str.startIndex.stride(to: str.endIndex, by: 2) { } // fatal error
我收到以下运行时异常
致命错误:无法增加 endIndex
只是创建StrideTo<String.CharacterView.Index>
然而,上面,(let foo = str.startIndex.stride(to: str.endIndex, by: 2)
) 不会产生错误,仅当尝试跨步/迭代或对其进行操作时 (.next()
?).
- 出现这个运行时异常的原因是什么;是否符合预期(误用符合
Stridable
)?
我在用着斯威夫特2.2 and Xcode 7.3。详细信息如下。
编辑添加:找到错误源
仔细阅读我的问题后,似乎错误确实发生在next()
的方法StrideToGenerator
(参见本文底部),特别是在以下标记行
let ret = current
current += stride // <-- here
return ret
即使最后一次更新current
永远不会被返回(在下次调用next()
),最终提前current
索引到大于或等于的值_end
产生上面的特定运行时错误(对于Index
type String.CharacterView.Index
).
(0..<4).startIndex.advancedBy(4) // OK, -> 4
"foo".startIndex.advancedBy(4) // fatal error: cannot increment endIndex
然而,仍然存在一个问题:
- 这是一个错误吗
next()
的方法StrideToGenerator
,或者只是由于误用而弹出的错误String.CharacterView.Index
符合Stridable
?
Related
以下问答相关在除以下步骤之外的步骤中迭代字符的主题+1
,即使这两个问题不同,也值得包含在这个问题中。
- 在 for 语句中使用 String.CharacterView.Index.successor() https://stackoverflow.com/questions/36194060/using-string-characterview-index-successor-in-for-statements/
特别注意@Sulthan:巧妙的解决方案 https://stackoverflow.com/a/36207901/4573247在上面的线程中。
Details
(对我自己的大量细节/调查表示歉意,如果您可以在没有此处详细信息的情况下回答我的问题,请跳过这些部分)
The String.CharacterView.Index type http://swiftdoc.org/v2.2/type/String.CharacterView.Index/描述角色位置,并且:
- 符合
Comparable
(所以,Equatable
),
- 包含的实现
advancedBy(_:)
and distanceTo(_:)
.
因此,可以直接使其符合协议Strideable http://swiftdoc.org/v2.2/protocol/Strideable/,利用Stridable
:s 方法的默认实现stride(through:by:)
and stride(to:by:)
。下面的例子将重点关注后者(与前者的类似问题):
...
func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self>
返回值的序列(自我,自我+跨步,自我+跨步+
大步走,...最后)其中,last 是级数中的最后一个值小于 end.
符合Stridable
并大步走过1
: 都好
延伸String.CharacterView.Index
to Stridable
并大步走过1
工作正常:
extension String.CharacterView.Index : Strideable { }
var str = "0123"
// stride by 1: all good
str.startIndex.stride(to: str.endIndex, by: 1).forEach {
print($0,str.characters[$0])
} /* 0 0
1 1
2 2
3 3 */
对于偶数个索引str
以上(指数0..<4
),这也适用于跨步2
:
// stride by 2: OK for even number of characters in str.
str.startIndex.stride(to: str.endIndex, by: 2).forEach {
print($0,str.characters[$0])
} /* 0 0
2 2 */
然而,对于某些跨越的情况>1
: 运行时异常
对于奇数个索引和步长2
但是,跨过字符视图索引的跨度会产生运行时错误
// stride by 2: fatal error for odd number of characters in str.
str = "01234"
str.startIndex.stride(to: str.endIndex, by: 2).forEach {
print($0,str.characters[$0])
} /* 0 0
2 2
fatal error: cannot increment endIndex */
我自己的调查
我自己对此进行的调查使我怀疑该错误来自next()
的方法StrideToGenerator结构 http://swiftdoc.org/v2.2/type/StrideToGenerator/,可能当这个方法调用时+=
在可跨过的元素上
public func += <T : Strideable>(inout lhs: T, rhs: T.Stride) {
lhs = lhs.advancedBy(rhs)
}
(来自 Swift 源代码的一个版本swift/stdlib/public/core/Stride.swift https://github.com/apple/swift/blob/174d475833838fda986120dabc009377ffaa89b6/stdlib/public/core/Stride.swift这在某种程度上对应于 Swift 2.2)。鉴于以下问答:
-
快速修剪字符串的结尾,在运行时出错 https://stackoverflow.com/questions/29277746/trim-end-off-of-string-in-swift-getting-error-at-runtime,
-
Swift distance() 方法抛出致命错误:无法增加 endIndex https://stackoverflow.com/questions/27191865/swift-distance-method-throws-fatal-error-can-not-increment-endindex,
我们可能怀疑我们可能需要使用String.CharacterView.Index.advancedBy(_:limit:)
而不是...advancedBy(_:)
多于。 但是从我所看到的来看,next()
中的方法StrideToGenerator
防止指数超出限制。
编辑补充:错误的根源似乎确实位于next()
中的方法StrideToGenerator
:
// ... in StrideToGenerator
public mutating func next() -> Element? {
if stride > 0 ? current >= end : current <= end {
return nil
}
let ret = current
current += stride /* <-- will increase current to larger or equal to end
if stride is large enough (even if this last current
will never be returned in next call to next()) */
return ret
}
即使最后一次更新current
永远不会被返回(在下次调用next()
),最终提前current
索引到大于或等于的值end
产生上面的特定运行时错误,对于Index
type String.CharacterView.Index
.
(0..<4).startIndex.advancedBy(4) // OK, -> 4
"foo".startIndex.advancedBy(4) // fatal error: cannot increment endIndex
这是否被视为错误,或者是String.CharacterView.Index
根本不打算(直接)符合Stridable
?