使 String.CharacterView.Index 符合 Strideable:使用 stride(to:by:) 时出现致命错误:“无法增加 endIndex ”

2024-04-30

问题:

当试图跨过去时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?


简单声明协议一致性

extension String.CharacterView.Index : Strideable { }

编译是因为String.CharacterView.Index符合BidirectionalIndexType , and ForwardIndexType/BidirectionalIndexType有默认方法实现advancedBy() and distanceTo()根据要求Strideable.

Strideable具有默认的协议方法实现 为了stride():

extension Strideable {
    // ...
    public func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self>
}

因此,唯一“直接”实现的方法String.CharacterView.Index是——据我所知——successor() and predecessor()方法来自BidirectionalIndexType.

正如您已经想到的,默认方法实现stride()不能很好地配合String.CharacterView.Index.

但是始终可以为具体类型定义专用方法。problems的制作String.CharacterView.Index符合Strideable see 瓦萨尔·马诺特的回答 https://stackoverflow.com/a/36206399/1187415下面以及评论中的讨论——我花了一段时间才明白他的意思:)

这是一个可能的实现stride(to:by:)方法用于String.CharacterView.Index:

extension String.CharacterView.Index {
    typealias Index = String.CharacterView.Index

    func stride(to end: Index, by stride: Int) -> AnySequence<Index> {

        precondition(stride != 0, "stride size must not be zero")

        return AnySequence { () -> AnyGenerator<Index> in
            var current = self
            return AnyGenerator {
                if stride > 0 ? current >= end : current <= end {
                    return nil
                }
                defer {
                    current = current.advancedBy(stride, limit: end)
                }
                return current
            }
        }
    }
}

这似乎按预期工作:

let str = "01234"
str.startIndex.stride(to: str.endIndex, by: 2).forEach {
    print($0,str.characters[$0])
} 

Output

0 0
2 2
4 4
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使 String.CharacterView.Index 符合 Strideable:使用 stride(to:by:) 时出现致命错误:“无法增加 endIndex ” 的相关文章

  • Audiokit 修剪音频

    我正在制作音频编辑应用程序 我想修剪我的音频 对于音频编辑 我使用 AudioKit 框架 但我在教程和示例中找不到如何使用此框架修剪音频 异步导出允许设置开始和结束样本 https github com AudioKit AudioKit
  • CIAdditionCompositing 给出不正确的效果

    我正在尝试通过平均其他几个图像来创建图像 为了实现这一点 我首先将每个图像变暗 其系数等于我平均的图像数量 func darkenImage by multiplier CGFloat gt CIImage let divImage CII
  • 在completionHandlers中存储值 - Swift

    我正在创建一个completionHandler它返回一个字典 但是当我在另一个类中调用这个方法时 它的值是零 func fetchLatestPosts completionHandler responseDict NSDictionar
  • 如何无限地每1分钟运行一个iOS应用程序?

    我制作了一个应用程序 需要每 1 分钟向服务器发送一次位置和状态更新 我尝试了以下方法 但没有一个能帮助我 有什么解决办法吗 1 NSTimer 很多人建议这样做 但问题出在后台模式上 它只能工作 20 分钟 该应用程序停止发送数据后 2
  • skView.ignoreSiblingOrder 在 swift 中的重要性/效率?

    这样做有多重要 高效skView ignoreSiblingOrder true初始化场景时 现在 我将其设置为 true 但由于某种原因 当我从 MainMenu 场景启动 GameScene 时 它 会在我的角色之前加载背景 即使背景的
  • 删除具有estimatedItemSize 的项目时 UICollectionView 单元格大小会调整

    我有一个简单的项目 其中的故事板仅包含一个UICollectionViewController 使用 Xcode 7 1 1 为 iOS 9 1 构建 class ViewController UICollectionViewControl
  • 在 Swift 中使用 commitEditingStyle 动态删除 UITable 部分

    我正在处理一个无法解决的问题 我有一个来自客户数据库数组的名称表 每个客户在其他数据成员中都有一个名称属性 我可以成功删除某个部分中的行 但我不能删除该部分 当该部分中的最后一行被删除时 该部分必须消失 I got NSInternalIn
  • SwiftUI - 预览时未知的预览提供程序“ContentView_Previews_”。发生在一个全新的项目中

    我有这个简单的观点 import SwiftUI struct ContentView View var body some View Text Hello struct ContentView Previews PreviewProvid
  • iOS 11 浮动 TableView 标题

    有一个应用程序包含多个部分 展开 时每个部分有几行 折叠 时没有 每个部分都有一个部分标题 使用以下子类重用它们UITableViewHeaderFooterView等等 到目前为止一切顺利 然后在 iOS 11 中 我使用了可视化调试器
  • 使用prepareForSegue传递数据

    我试图将数据从viewController 1传递到viewController2 我有2个按钮和1个segue 因此有一个segue标识符 这2个按钮 按下时每个按钮应显示 1个标签用于显示标题 1个textView用于显示定义 我很难显
  • UITesting、XCTest 当前 ViewController 类

    简单的问题 我有一个按钮可以执行到下一个视图控制器的操作 我想写 UI XCTest 来告诉我它是否打开了我想要的视图控制器 UI 测试框架无法访问您的应用程序代码 这使得无法对实例进行类断言 你不能够directly告诉屏幕上的控制器的类
  • 如何使用 SwiftUI 获取多个屏幕上的键盘高度并移动按钮

    以下代码获取键盘显示时的键盘高度 并将按钮移动键盘高度 在转换源 ContentView 和转换目标 SecibdContentView 处以相同的方式执行此移动 但按钮在转换目标处不移动 如何使按钮在多个屏幕上移动相同 import Sw
  • Swift:检查 UISearchBar.text 是否包含 url

    如何检查 UISearchBar text 是否包含 URL 我想做这样的事情 if searchBar text NSTextCheckingType Link 但我收到错误 String is not convertible to NS
  • 带约束的嵌套集合视图的意外行为 (Swift 4)

    我的表格视图中有一个单元格 其中包含水平分页集合视图 该集合视图的每个页面内都有一个垂直集合视图 为了避免 滚动滚动 问题 我在垂直集合视图中禁用了垂直滚动 垂直集合视图的单元格计数不是静态的 可以是任意数字 因此 这会产生一个问题 集合视
  • 如何将CIFilter应用到UIView上?

    根据Apple docs 过滤属性CALayer不支持iOS 当我使用正在申请的应用程序之一时CIFilter to UIView即 Splice Funimate 和 Artisto 的视频编辑器 Videoshow FX 这意味着我们可
  • 在 Swift 中以编程方式为 iOS 制作带有名字首字母的图像,例如 Gmail

    我需要在 UITableView 中显示与其姓名相对应的每个用户的个人资料图片 在下载图像之前 我需要显示一张带有他名字的第一个字母的图像 就像在 GMail 应用程序中一样 如何在 Swift for iOS 中以编程方式执行此操作 不需
  • UILabel 中的文本未垂直居中

    我使用以下代码创建了一个标签 func setupValueLabel valueLabel numberOfLines 1 valueLabel font UIFont name Avenir Black size 50 valueLab
  • 如何在 swiftUI (macOS) 中检测按键按下和释放

    除了标题之外没什么可说的 我希望能够在按下按键和释放按键时 在 macOS 上 在 swiftUI 视图中执行操作 在 swiftUI 中是否有任何好的方法可以做到这一点 如果没有 有什么解决方法吗 不幸的是 键盘事件处理是其中一个令人痛苦
  • 如何去掉 UIWebView 上的状态栏背景?

    从 iOS 11 开始 当UIWebView全屏时 状态栏上会出现与屏幕颜色相同的假背景UIWebView背景 有人知道如何摆脱它吗 甚至添加IUWebView到故事板并使其全屏将使状态栏背景出现 我一直在尝试编辑 UIWebView 的大
  • 以编程方式从底部裁剪图像

    我正在开发自定义相机应用程序 一切进展顺利 但我在从底部裁剪图像时遇到了问题 即 裁剪后的图像与原始图像具有完全相同的宽度 但高度将为原始图像的 1 3 并且必须从底部开始 斯威夫特3解决方案 func cropBottomImage im

随机推荐