Swift3随机扩展方法

时间:2016-11-02 01:55:11

标签: ios swift swift3

我使用此扩展方法生成随机数:

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?我有什么建议让事情变得更容易吗?

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

3 个答案:

答案 0 :(得分:4)

在Swift 3中有四种Range结构:

  • "x" ..< "y"Range<T>
  • "x" ... "y"ClosedRange<T>
  • 1 ..< 5CountableRange<T>
  • 1 ... 5CountableClosedRange<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?)。

它使用CountableRangeCountableClosedRange这一事实 是集合,,实际上是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)