如何在Swift中检查数组索引是否超出范围

3

我举一个例子,比如这个请求:

mannschaft18teamid = results2.data.table[17].team_id 

假设第17个数组元素不存在。如果它不存在,我该如何设置它的标准值?我希望将其值设置为字符串“not existing”。

可能像这样:

mannschaft18teamid = results2.data.table[17].team_id ?? "not existing"

它无法正常工作。模拟器会崩溃并显示:Thread 1: Fatal error: Index out of range

即使不设置值,也没有问题。如果忽略那一行也可以。


1
https://dev59.com/SF8e5IYBdhLWcg3wNINp - roadRunner
4个回答

4
如果results2.data.table是数组,请尝试以下操作:
let index = 17
if results2.data.table.indices.contains(index) {
    mannschaft18teamid = results2.data.table[index].team_id
} else {
    mannschaft18teamid = "not existing"
}

你遇到了“索引超出范围”的错误,所以你应该使用indices.contains(index)来检查索引是否存在。更多信息请参阅此处


4

如果您需要此语法,则可以扩展 RandomAccessCollection 并实现一个下标,该下标从数组返回一个可选值:

extension RandomAccessCollection {
    subscript(index: Index) -> Element? {
        self.indices.contains(index) ? (self[index] as Element) : nil
    }
}

通过这种方式,您可以像这样做:

let arr = ["a", "b", "c"]
print(arr[99] ?? "not existing") // "not existing"

要小心确保在上下文中推断出 Optional 类型,例如使用 ?? 或可选链式调用 arr[99]?.prop,否则以下代码将仍然表现正常,即会导致 索引超出范围 错误:

let v = arr[99] // error

或者,您可以定义一个带有默认值的下标(就像Dictionary一样):

extension RandomAccessCollection {
    subscript(index: Index, default defaultValue: @autoclosure () -> Element) -> Element {
        self.indices.contains(index) ? self[index] : defaultValue()
    }
}

let arr = [1,2,3]
print(arr[9, default: 99]) // 99

2
如果您不需要设置任何值,您应该使用一个守卫语句来获取索引处的元素。
guard results2.data.table.count >= 18 else {
    // Bad path, early exit scope
    return 
}

// Happy path, keep going
mannschaft18teamid = results2.data.table[17].team_id

但需要注意的是,守卫(guard)是用于在意外情况下提前退出作用域,因此之后的任何内容都不会被执行。如果您想让程序继续执行,则应使用if let语句:

if let results2.data.table.count >= 18 {
    // Index exists, do stuff
   mannschaft18teamid = results2.data.table[17].team_id
}

如果您想继续使用nil合并操作符(??)来提供默认值,则应实现一个扩展来安全地访问集合中的项。您可以阅读其他答案或参考答案。

1
当数组不包含该索引时,会发生“索引超出范围”错误--而不是它是否为nil或非nil。 - aheze
2
@aheze 你说得完全正确,我错了。我已经纠正了它。 - banderson

1

最好使用可选扩展,如果索引处的元素不存在,则返回nil

扩展

extension Collection where Indices.Iterator.Element == Index {
    subscript (optional index: Index) -> Iterator.Element? {
        return indices.contains(index) ? self[index] : nil
    }
}

使用方法:

mannschaft18teamid = results2.data.table[optional: 17]?.team_id ?? "not existing"

我尝试在两个Swift文件中使用这个。其中一个文件可以正常工作,而另一个文件出现了“Invalid redeclaration of 'subscript(optional:)'”的错误。我需要做什么改变? - submariner
1
只需声明一次,随处可用。 - Frankenstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接