我意识到Swift书籍提供了一个随机数生成器的实现。复制和粘贴这个实现是最佳实践吗?或者有没有这样的库,我们现在就可以使用?


当前回答

对于0到n-1之间的随机整数,使用arc4random_uniform(n)。

let diceRoll = Int(arc4random_uniform(6) + 1)

将结果转换为Int,这样你就不必显式地将你的vars类型为UInt32(这看起来不像swifty)。

其他回答

对于0到n-1之间的随机整数,使用arc4random_uniform(n)。

let diceRoll = Int(arc4random_uniform(6) + 1)

将结果转换为Int,这样你就不必显式地将你的vars类型为UInt32(这看起来不像swifty)。

细节

xCode 9.1, Swift 4

面向数学的解(1)

import Foundation

class Random {

    subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
        get {
            return rand(min-1, max+1)
        }
    }
}

let rand = Random()

func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
    let _min = min + 1
    let difference = max - _min
    return T(arc4random_uniform(UInt32(difference))) + _min
}

溶液使用方法(1)

let x = rand(-5, 5)       // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10]       // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

面向程序员的解决方案(2)

不要忘记在这里添加面向数学的解决方案(1)代码

import Foundation

extension CountableRange where Bound : BinaryInteger {

    var random: Bound {
        return rand(lowerBound-1, upperBound)
    }
}

extension CountableClosedRange where Bound : BinaryInteger {

    var random: Bound {
        return rand[lowerBound, upperBound]
    }
}

溶液使用方法(2)

let x = (-8..<2).random           // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random           // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random       // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]

完整的样品

不要忘记在这里添加溶液(1)和溶液(2)的代码

private func generateRandNums(closure:()->(Int)) {

    var allNums = Set<Int>()
    for _ in 0..<100 {
        allNums.insert(closure())
    }
    print(allNums.sorted{ $0 < $1 })
}

generateRandNums {
    (-8..<2).random
}

generateRandNums {
    (0..<10).random
}

generateRandNums {
    (-10 ... -2).random
}

generateRandNums {
    rand(-5, 5)
}
generateRandNums {
    rand[0, 10]
}

样品结果

@jstn的回答很好,但有点啰嗦。Swift被称为面向协议的语言,因此我们可以通过为协议扩展添加默认实现,而不必为整数族中的每个类实现样板代码来实现相同的结果。

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}

现在我们可以做:

let i = Int.arc4random()
let j = UInt32.arc4random()

其他的整数类都是可以的。

你可以像这样使用GeneratorOf:

var fibs = ArraySlice([1, 1])
var fibGenerator = GeneratorOf{
    _ -> Int? in
    fibs.append(fibs.reduce(0, combine:+))
    return fibs.removeAtIndex(0)
}

println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())

我想补充现有的答案,在Swift书中的随机数生成器的例子是一个线性同余生成器(LCG),这是一个非常有限的一个,不应该除了必须平凡的例子,其中随机性的质量根本不重要。LCG永远不应该用于加密目的。

Arc4random()要好得多,可以用于大多数目的,但不应该用于加密目的。

如果您想要保证加密安全的内容,请使用SecCopyRandomBytes()。请注意,如果您将随机数生成器构建到某个东西中,其他人可能最终(错误地)将其用于加密目的(例如密码、密钥或盐生成),那么无论如何您都应该考虑使用SecCopyRandomBytes(),即使您的需要并不完全需要这样做。