let numbers = [10, 20, 30, 40, 50]
if let i = numbers.index(numbers.startIndex,
offsetBy: 5,
limitedBy: numbers.endIndex) {
print(numbers[i]) //Fatal error: Index out of range
}
endIndex is not exactly what you expect it to be - it's past the end (endIndex | Apple Developer Documentation). And index method you are using expects limitedBy parameter to be a valid array index so it could use it as a fallback. So you need to pass numbers.index(before: numbers.endIndex) instead.
Yes, I almost never use these methods on Arrays, since it much simpler to express it via simple arithmetic. When it comes to String for example, or working with generic collections, it's a powerful API on collection, and you it's good you are getting more familiar with it anyway.
let numbers = [10, 20, 30, 40, 50]
let offset = 5
let index = offset + numbers.startIndex
if index >= numbers.startIndex && index < numbers.endIndex {
print(numbers[index])
}
Just to colour in some reasoning behind this, which also helps with remembering it:
Setting the endIndex to "one past the end" lets you write code that doesn't need to have a special case for empty collections. std::end does the same in C++
If we instead define endIndex to be "the last element valid instead", then it breaks down for empty collections: because they don't have any elements to point to, you'd need to implement a special-case for it, which must break the rule.
You could design this with 3 possible values (that I can think of), which all suck:
0: in that case, then you can't distinguish between "has one element, at index 0", or "has no elements"
-1: now you have cases where you end index can be smaller than your start index
Some other sentinel like Int.min
In any case, you need to litter you code with special cases for empty collections.
With the current design, startIndex..<endIndex is always valid for Array.
i just really really wish that doccomment had an example of the boundary condition, that shows you get nil when you pass 5 for the offsetBy, because i remember being confused about the same thing when i was first starting to use Swift.
the documentation for String.index(_:offsetBy:limitedBy:) has the same issue, it gives examples for offsetBy: 4 and offsetBy: 6, but not 5 for some reason.