A Range
in Swift is just two end points. A Range
can represent things like a selection in some text or a portion of an Array
.
A pseudo-representation of Range
looks like this...
struct Range<T> {
var startIndex: T
var endIndex: T
}
The T
is restricted a little bit and must be comparable. That's because Range
needs to be able to make sure that the startIndex
is less than the endIndex
, so every index value in Range
must be able to be compared.
There are other more capable Ranges
like CountableRange
. A CountableRange
contains consecutive values which can be iterated over or indexed into.
In fact if the type of the upper and lower bound is an Int
(more specifically is "strideable" by Int) swift makes it a CountableRange
. Which in turn becomes a sequence which is enumeratable with for in
.
for i in 0..<20 { ... }
Floating point numbers are an example of a type that doens't stride by Int
, they stride by a floating point value. so 0.5...15.25
is just a Range
, not a CountableRange
which is needed for a for in
.
But there is a global function called stride
that will create a CountableRange
from floating point values. It takes a from
and through
argument to specify where to start and stop and also a by
which takes a value of what to step through the sequence with.
for i in stride(from: 0.5, through: 15.25, by: 0.3) {
...
}
This is actually a type of
CountableRange
calledClosedCountableRange
because it goes through to the last value in the sequence (15.25)
As an aside arrays of Ints and dictionaries are both sequences.
Creating A Range
Either ..<
which excludes the upper bound or ...
which is includes both bounds.
let array = ["a", "b", "c", "d"]
let a = array[2...3] // ["c", "d"]
let b = array[2..<3] // ["c"]
Array index out of bound or a lower bound that is greater than the upper bound will produce a runtime crash
// runtime crash
let array = ["a", "b", "c", "d"]
let c = array[6...8]
let d = array[4...1]
Strings
A subrange of a String
is not a Range<Int>
it's a Range<String.Index>
// this != "ll", and in fact won't even compile
let e = "hello"[2..<4]
// this is possible
let f = "hello"[start..<end]