当我在 index(_ , offsetBy , limitBy) 函数中将 offsetBy 值设置为等于 endIndex 值时,为什么 swift 会给出错误?

Mo *_*ati 4 swift

这是代码:

1-offsetBy 为 4 或更少时就可以了

    let someString = "hello"

    if let someIndex = someString.index(someString.startIndex, 
                        offsetBy: 4, limitedBy: someString.endIndex){
       someString[someIndex]
    }
    // Prints "o"
Run Code Online (Sandbox Code Playgroud)

2- 当 offsetBy 为 6 或更大时就可以了

    if let someIndex = someString.index(someString.startIndex, 
                        offsetBy: 6, limitedBy: someString.endIndex){
       someString[someIndex]
    }
    // Prints "nil"
Run Code Online (Sandbox Code Playgroud)

3-但是当offsetBy为5时它会出错

    if let someIndex = someString.index(someString.startIndex, 
                        offsetBy: 5, limitedBy: someString.endIndex){
       someString[someIndex]
    }
    // error
Run Code Online (Sandbox Code Playgroud)

错误是:

错误:Playground 执行中止:错误:执行被中断,原因:EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)。进程已留在中断点,使用“thread return -x”返回到表达式求值之前的状态。

Ham*_*ish 5

问题在于给定的限制index(_:offsetBy:limitedBy:)是结果的包含范围。因此与

let someString = "hello"
Run Code Online (Sandbox Code Playgroud)

返回的索引

someString.index(someString.startIndex, offsetBy: 5, limitedBy: someString.endIndex)
Run Code Online (Sandbox Code Playgroud)

will be someString.endIndex,它是超过结束索引的,因此不是字符串下标的有效索引。

因此,一个简单的解决方案是在语句中添加一个条件if,以检查返回的索引不是endIndex

let someString = "hello"
let offset = 5

if let someIndex = someString.index(someString.startIndex,
                                    offsetBy: offset,
                                    limitedBy: someString.endIndex
                                    ), someIndex != someString.endIndex {
    print(someString[someIndex])
}
Run Code Online (Sandbox Code Playgroud)

或者更好的选择是使用CharacterViewsindices属性来获取有效索引的集合,以使用(不包括endIndex)下标,并使用dropFirst(_:)andfirst来获取给定偏移处的索引:

if let index = someString.characters.indices.dropFirst(offset).first {
    print(someString[index])
}
Run Code Online (Sandbox Code Playgroud)

这利用了以下事实:dropFirst(_:)需要删除元素的上限,如果大于集合的计数,则返回空子序列,以及first返回nil空集合的事实。