J'utilisais cette méthode d'extension pour générer un nombre random:
func Rand(_ range: Range<UInt32>) -> Int { return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound + 1)) }
Je l'ai aimé b / c ce n'était pas un non-sens, vous venez de l'appeler comme ceci:
let test = Rand(1...5) //generates a random number between 1 and 5
Honnêtement, je ne sais pas pourquoi les choses doivent être si compliquées dans Swift mais je m'égare ..
Donc, je reçois une erreur maintenant dans Swift3
No '...' candidates produce the expected contextual result type 'Range<UInt32>'
Est-ce que quelqu'un pourrait savoir ce que cela signifie ou comment je pourrais faire fonctionner ma superbe fonction Rand? Je suppose que x … y ne crée plus Ranges ou x..y doit être explicitement défini comme UInt32? Un conseil pour moi de rendre les choses un peu plus faciles?
Merci beaucoup, appréciez votre time!
Dans Swift 3, il y a quatre structures de Range:
"x" ..< "y"
⇒ Range<T>
"x" ... "y"
⇒ ClosedRange<T>
1 ..< 5
⇒ CountableRange<T>
1 ... 5
⇒ CountableClosedRange<T>
(Les opérateurs ..<
et ...
sont surchargés de sorte que si les éléments sont ssortingdables (iterators à access random, par exemple des nombres et des pointeurs), une plage Countable sera returnnée, mais ces opérateurs peuvent toujours returnner des Plages simples pour satisfaire le vérificateur de type. .)
Puisque Range et ClosedRange sont des structures différentes, vous ne pouvez pas les convertir implicitement les unes avec les autres, et donc l'erreur.
Si vous voulez que Rand accepte une ClosedRange ainsi que Range, vous devez le surcharger:
// accepts Rand(0 ..< 5) func Rand(_ range: Range<UInt32>) -> Int { return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound)) } // accepts Rand(1 ... 5) func Rand(_ range: ClosedRange<UInt32>) -> Int { return Int(range.lowerBound + arc4random_uniform(range.upperBound + 1 - range.lowerBound)) }
Une bonne solution est présentée dans Generic Range Algorithms (basé sur Comment être DRY sur les gammes et les gammes fermées? Dans la list de diffusion swift-users).
Il utilise le fait que CountableRange
et CountableClosedRange
sont des collections, et en fait un RandomAccessCollection
.
Vous pouvez donc définir une seule fonction (générique) qui accepte à la fois les plages d'entiers ouverts et fermés:
func rand<C: RandomAccessCollection>(_ coll: C) -> C.Iterator.Element { precondition(coll.count > 0, "Cannot select random element from empty collection") let offset = arc4random_uniform(numericCast(coll.count)) let idx = coll.index(coll.startIndex, offsetBy: numericCast(offset)) return coll[idx] } rand(1...5) // random number between 1 and 5 rand(2..<10) // random number between 2 and 9
mais aussi:
rand(["a", "b", "c", "d"]) // random element from the array
Alternativement comme une méthode d'extension de protocole:
extension RandomAccessCollection { func rand() -> Iterator.Element { precondition(count > 0, "Cannot select random element from empty collection") let offset = arc4random_uniform(numericCast(count)) let idx = index(startIndex, offsetBy: numericCast(offset)) return self[idx] } } (1...5).rand() (2..<10).rand() ["a", "b", "c", "d"].rand()
Vous pouvez réécrire Rand()
pour utiliser Int
si c'est votre cas d'utilisation principal:
func Rand(_ range: Range<Int>) -> Int { let distance = UInt32(range.upperBound - range.lowerBound) return range.lowerBound + Int(arc4random_uniform(distance + 1)) }
Ou comme le souligne kennytm, utilisez Rand(1..<6)