Swift3随机扩展方法

我正在使用此扩展方法生成一个随机数:

func Rand(_ range: Range) -> 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' 

有谁知道这意味着什么,或者我怎么能让我真棒的兰德function再次运作? 我猜x … y不再创建Ranges或x..y必须明确定义为UInt32? 我有什么建议让事情变得更容易吗?

非常感谢,感谢您的时间!

在Swift 3中有四种Range结构:

  • "x" ..< "y"Range
  • "x" ... "y" ClosedRange
  • 1 ..< 5 CountableRange
  • 1 ... 5 CountableClosedRange

(运算符..<...被重载,因此如果元素是可争分的(随机访问迭代器,例如数字和指针),将返回可计数范围。但是这些运算符仍然可以返回普通范围以满足类型检查器。)

由于Range和ClosedRange是不同的结构,因此您不能隐式地将它们相互转换,从而导致错误。

如果你想让Rand接受一个ClosedRange以及Range,你必须重载它:

 // accepts Rand(0 ..< 5) func Rand(_ range: Range) -> Int { return Int(range.lowerBound + arc4random_uniform(range.upperBound - range.lowerBound)) } // accepts Rand(1 ... 5) func Rand(_ range: ClosedRange) -> Int { return Int(range.lowerBound + arc4random_uniform(range.upperBound + 1 - range.lowerBound)) } 

在通用范围算法 (基于如何在范围和封闭范围内干燥?在swift-users邮件列表中)中提供了一个很好的解决方案。

它使用了CountableRangeCountableClosedRange都是集合的事实,实际上是RandomAccessCollection

因此,您可以定义一个接受开放和闭合整数范围的单个(通用)函数:

 func rand(_ 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() 

如果这是您的主要用例,您可以重写Rand()以使用Int

 func Rand(_ range: Range) -> Int { let distance = UInt32(range.upperBound - range.lowerBound) return range.lowerBound + Int(arc4random_uniform(distance + 1)) } 

或者正如肯尼特指出的那样,使用Rand(1..<6)