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..<yandx...yproduced the same type,Range<T>. Now these expressions can produce one of the four types:Range,CountableRange,ClosedRange,CountableClosedRange. We splitRangeintoRangeandClosedRangetypes to allow closed ranges that include the maximum value of the type (for example,0...Int8.maxworks now). The plain range types and their ~Countable counterparts differ in the capabilities:
Range<Bound>andClosedRange<Bound>now only requireComparablefor the bound. This allows you to create aRange<String>.RangeandClosedRangecan’t be iterated over (they are not collections anymore), since a value that is merelyComparablecannot be incremented.CountableRangeandCountableClosedRangerequireStrideabefrom their bound and they conform toCollectionso 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..<10infers aCountableRangeand 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