使用 crypto/rand 通过 rand.Perm 生成排列

Rol*_*lig 8 random go

Go 有两个随机数包:

  • crypto/rand,它提供了一种获取随机字节的方法
  • math/rand,它有一个很好的打乱整数的算法

我想使用Perm中的算法math/rand,但为其提供高质量的随机数。

由于这两个rand包是同一标准库的一部分,因此应该有一种方法将它们组合起来,以便crypto/rand提供用于math/rand.Perm生成排列的良好随机数源。

这里(以及Playground上)是我编写的用于连接这两个包的代码:

package main

import (
    cryptoRand "crypto/rand"
    "encoding/binary"
    "fmt"
    mathRand "math/rand"
)

type cryptoSource struct{}

func (s cryptoSource) Int63() int64 {
    bytes := make([]byte, 8, 8)
    cryptoRand.Read(bytes)
    return int64(binary.BigEndian.Uint64(bytes) >> 1)
}

func (s cryptoSource) Seed(seed int64) {
    panic("seed")
}

func main() {
    rnd := mathRand.New(&cryptoSource{})
    perm := rnd.Perm(52)
    fmt.Println(perm)
}
Run Code Online (Sandbox Code Playgroud)

这段代码有效。理想情况下,我不想cryptoSource自己定义类型,而只是将两个rand包粘在一起,以便它们一起工作。那么是否有这种类型的预定义版本cryptoSource

Jim*_*imB 4

这基本上就是你需要做的。您并不经常需要加密安全的随机源来进行 的常见使用math/rand,因此没有提供适配器。通过直接在值中分配缓冲区空间,而不是在每次调用时分配一个新切片,可以使实现稍微更高效。然而,万一读取操作系统随机源失败,则需要恐慌以防止返回无效结果。

type cryptoSource [8]byte

func (s *cryptoSource) Int63() int64 {
    _, err := cryptoRand.Read(s[:])
    if err != nil {
        panic(err)
    }
    return int64(binary.BigEndian.Uint64(s[:]) & (1<<63 - 1))
}
Run Code Online (Sandbox Code Playgroud)