我使用此扩展方法生成随机数:
func Rand(_ range: Range<UInt32>) -> Int {
return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound + 1))
}
我喜欢它b / c这不是废话,你只是这样叫:
let test = Rand(1...5) //generates a random number between 1 and 5
老实说,我不知道为什么Swift中的事情需要如此复杂,但我离题了..
所以我现在在Swift3中收到错误
No '...' candidates produce the expected contextual result type 'Range<UInt32>'
有谁知道这意味着什么,或者我怎么能让我真棒的兰德功能再次运作?我猜x ... y不再创建范围或x..y必须明确定义为UInt32?我有什么建议让事情变得更容易吗?
非常感谢,感谢您的时间!
答案 0 :(得分:4)
在Swift 3中有四种Range结构:
"x" ..< "y"
⇒Range<T>
"x" ... "y"
⇒ClosedRange<T>
1 ..< 5
⇒CountableRange<T>
1 ... 5
⇒CountableClosedRange<T>
(运算符..<
和...
被重载,因此如果元素是可争分的(随机访问迭代器,例如数字和指针),则会返回可计数范围。但是这些运算符仍然可以返回普通的范围,以满足类型检查。)
由于Range和ClosedRange是不同的结构,因此你不能隐式地将它们相互转换,从而产生错误。
如果你想让Rand接受一个ClosedRange和Range,你必须重载它:
// 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))
}
答案 1 :(得分:4)
Generic Range Algorithms中提供了一个很好的解决方案 (基于swift-users邮件列表中的How to be DRY on ranges and closed ranges?)。
它使用CountableRange
和CountableClosedRange
这一事实
是集合,,实际上是RandomAccessCollection
。
因此,您可以定义一个接受open和closed的单个(通用)函数 整数范围:
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
但也是:
rand(["a", "b", "c", "d"]) // random element from the array
或者作为协议扩展方法:
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()
答案 2 :(得分:0)
如果这是您的主要用例,您可以重写Rand()
以使用Int
:
func Rand(_ range: Range<Int>) -> Int {
let distance = UInt32(range.upperBound - range.lowerBound)
return range.lowerBound + Int(arc4random_uniform(distance + 1))
}
或者正如kennytm指出的那样,使用Rand(1..<6)