I was using this extension method to generate a random number:
func Rand(_ range: Range<UInt32>) -> Int {
return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound + 1))
}
I liked it b/c it was no nonsense, you just called it like this:
let test = Rand(1...5) //generates a random number between 1 and 5
I honestly don't know why things need to be so complicated in Swift but I digress..
So i'm receiving an error now in Swift3
No '...' candidates produce the expected contextual result type 'Range<UInt32>'
Would anyone know what this means or how I could get my awesome Rand function working again? I guess x...y no longer creates Ranges or x..y must be explicitly defined as UInt32? Any advice for me to make things a tad easier?
Thanks so much, appreciate your time!
A nice solution is presented in Generic Range Algorithms (based on How to be DRY on ranges and closed ranges? in the swift-users mailing list).
It uses the fact that both
CountableRange
andCountableClosedRange
are collections, and in fact aRandomAccessCollection
.So you can define a single (generic) function which accepts both open and closed integer ranges:
but also:
Alternatively as a protocol extension method:
In Swift 3 there are four Range structures:
"x" ..< "y"
⇒Range<T>
"x" ... "y"
⇒ClosedRange<T>
1 ..< 5
⇒CountableRange<T>
1 ... 5
⇒CountableClosedRange<T>
(The operators
..<
and...
are overloaded so that if the elements are stridable (random-access iterators e.g. numbers and pointers), a Countable Range will be returned. But these operators can still return plain Ranges to satisfy the type checker.)Since Range and ClosedRange are different structures, you cannot implicitly convert a them with each other, and thus the error.
If you want Rand to accept a ClosedRange as well as Range, you must overload it:
You could rewrite
Rand()
to useInt
if that is your primary use case:Or as kennytm points out, use
Rand(1..<6)