Explain the usage of the range class in the Migrating to Swift 2.3 or Swift 3 from Swift 2.2 article.
Described as follows:
In support of the collections changes, Range types also had some changes. Previously
x..<y
andx...y
produced the same type,Range<T>
. Now these expressions can produce one of the four types:Range
,CountableRange
,ClosedRange
,CountableClosedRange
. We splitRange
intoRange
andClosedRange
types to allow closed ranges that include the maximum value of the type (for example,0...Int8.max
works now). The plain range types and their ~Countable counterparts differ in the capabilities:
Range<Bound>
andClosedRange<Bound>
now only requireComparable
for the bound. This allows you to create aRange<String>
.Range
andClosedRange
can’t be iterated over (they are not collections anymore), since a value that is merelyComparable
cannot be incremented.CountableRange
andCountableClosedRange
requireStrideabe
from their bound and they conform toCollection
so that you can iterate over them.The
..<
and...
operators try to do the right thing and return the most capable range, so that code likefor i in 1..<10
infers aCountableRange
and continues to work. If you have a variable that is typed as one range type, and you need to pass it to an API that accepts a different type, use the initializers on range types to convert:
var r = 0..<10 // CountableRange<Int>
Range(r) // converts to Range<Int>
From Range<Bound>
and ClosedRange<Bound>
now only require Comparable
for the bound. This allows you to create a Range<String>
.
We can create a String generic Range.
// Range("a"..<"f")
let rangeStr = Range<String>.init(uncheckedBounds: ("a", "f"))
rangeStr.contains("b") // true
From Range
and ClosedRange
can’t be iterated over (they are not collections anymore), since a value that is merely Comparable
cannot be incremented.
ClosedRange
can't be used for iteration.
let closeRange = ClosedRange(uncheckedBounds: (1, 2))
for i in closeRange {
}
// error: type 'ClosedRange<Int>' does not conform to protocol 'Sequence'
From CountableRange
and CountableClosedRange
require Strideabe
from their bound and they conform to Collection
so that you can iterate over them.
CountableRange
and CountableClosedRange
can be used for iteration.
let myAry = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
let countableRange = CountableRange(uncheckedBounds: (1, 2))
for i in countableRange {
myAry[i] // 2
}
let countableCloseRange = CountableClosedRange(uncheckedBounds: (1, 2))
for i in countableCloseRange {
myAry[i] // 2, 3
}
About String and Range:
In Swift 2.x, we can do this:
let myString = "Hello World"
let myRange = Range<String.Index>(start: myString.startIndex, end: myString.startIndex.advancedBy(5))
let mySubString = myString.substringWithRange(myRange) // Hello
// or simply
let myString = "Hello World"
let myRange = myString.startIndex..<myString.startIndex.advancedBy(5)
let mySubString = myString.substringWithRange(myRange) // Hello
But in the Swift 3.0, the advancedBy
is unavailable, we need use index(_:offsetBy:)
.
let myString = "Hello World"
let myRange = myString.startIndex..<myString.index(myString.startIndex, offsetBy: 5)
let mySubString = myString.substring(with: myRange) // Hello