I want to know what does function
func formIndex(after i: inout Int)
According to documentation it says:
Replaces the given index with its successor.
But if we try to print out indices after using that function, it won't change:
var arr = [1,5,10, 15]
var index = arr.startIndex
arr.indices.forEach { index in
print("before form index \(index)")
}
arr.formIndex(after: &index)
arr.indices.forEach { index in
print("after form index \(index)")
}
Output:
before form index 0
before form index 1
before form index 2
before form index 3
after form index 0
after form index 1
after form index 2
after form index 3
It became even more confusing when I'm trying to print out value on that index:
var arr = [1,5,10, 15]
var index = arr.startIndex
arr.indices.forEach { index in
print("before form index \(index)")
}
print("index is \(index)")
print("arr zero index value before form index \(arr[0])")
print("arr first index value before form index \(arr[1])")
print("arr index value before form index \(arr[index])")
arr.formIndex(after: &index)
arr.indices.forEach { index in
print("after form index \(index)")
}
print("arr zero index value after form index \(arr[0])")
print("arr first index value after form index \(arr[1])")
print("arr index value after form index \(arr[index])")
Output:
before form index 0
before form index 1
before form index 2
before form index 3
index is 0
arr zero index value before form index 1
arr first index value before form index 5
arr index value before form index 1
after form index 0
after form index 1
after form index 2
after form index 3
arr zero index value after form index 1
arr first index value after form index 5
arr index value after form index 5
It looks like even index
value is 0
, we have different results for value at arr[0]
and arr[index]
.
You have misunderstood what formIndex(after:)
does. It does not modify the array in any way (it's not marked with mutating
after all). All it does is it sets the inout
parameter you passed, to the next index. Here is a demonstration:
var arr = [1,5,10,15]
var index = arr.startIndex
print(index) // prints "0"
arr.formIndex(after: &index)
print(index) // prints "1"
index
is initially 0. After you pass it to formIndex(after:)
, it becomes 1, because 1 is the next index after 0. This is all it does.
In the wording of the documentation, "replaces the given index" refers to setting the inout
parameter to a different value, and "its successor" refers to an index, not an element in the array.
Why would such a method be useful? Certainly, it is rarely useful to call this on an Array
. To get the next index of an Array
, you can just add 1. But if you are working with an arbitrary Collection
(writing generic code), this is very useful. An arbitrary Collection
doesn't necessarily use an incrementing sequence of Int
s as its indices. For example, Dictionary
is a Collection
, and it uses Dictionary.Index
values as its indices.
So the purpose of formIndex(after:)
is to give you a way to find the next index of a given index for any Collection
.
As an example, this is used in the implementation of firstIndex(of:)
:
public func firstIndex(of element: Element) -> Index? {
if let result = _customIndexOfEquatableElement(element) {
return result
}
var i = self.startIndex
while i != self.endIndex {
if self[i] == element {
return i
}
self.formIndex(after: &i)
}
return nil
}
In fact, you are required to implement a similar method - index(after:)
- when conforming to the Collection
protocol. The default implementation of formIndex(after:)
will set the inout
parameter to whatever index(after:)
returns.
You can think of formIndex(after:)
as just an "in-place" version of index(after:)
. By using an inout
parameter, the compiler can optimise it to a pass-by-reference (as if it is taking a pointer), which avoids copying the index value. Since the index type can be an arbitrary type, copying the index value might be expensive.