用习惯了python里面的random模块,随机数真的是顺手就来,这次用到了go,没想到生成的居然是伪随机数,首次生成虽然随机了,但是再次生成就一直是这个,这怎么搞,完全没随机啊,下面说一说踩过的坑!!!
文章目录
1. 首先来说一下什么是随机数
随机数,是使用一个确定性的算法计算出来随机数序。在程序开发中经常需要产生随机数,如随机数验证码登陆、作为唯一身份标识数据等等。
2. go中生成随机数的有两个包,分别是“math/rand”和“crypto/rand”,
- 前者实现了伪随机数生成器,
- 后者实现了用于加解密的跟安全的随机数生成器,当然,性能也就降下来了,毕竟鱼与熊掌不可兼得
3. 随机数生成
func main() {
for i:=0; i<10; i++ {
fmt.Print(rand.Intn(10), " ")
}
}
结果: 1 7 7 9 1 8 5 0 6 0 --> 生成的是
再来一次: 1 7 7 9 1 8 5 0 6 0 -->还是这个结果,这叫啥子随机数,查看文档,继续试验
4. 初始化随机种子函数(下面为官方文档说明)
func Seed(seed int64)
Seed uses the provided seed value to initialize the default Source to a deterministic state. If Seed is not called, the generator behaves as if seeded by Seed(1). Seed values that have the same remainder when divided by 2^31-1 generate the same pseudo-random sequence. Seed, unlike the Rand.Seed method, is safe for concurrent use.
我认为的意思就是系统每次都会先用Seed函数初始化系统资源,如果用户不提供seed参数,则默认用seed=1来初始化,这就是为什么每次都输出一样的值的原因,而且,Seed方法是并发安全的.
所谓种子,通俗理解可以理解为一个抽奖的奖池,我们自定义一个奖池,从我们的奖池中进行随机抽奖,种子就是我们奖池中的数据
5. 使用种子生成
func main() {
// 我们一般使用系统时间的不确定性来进行初始化
rand.Seed(time.Now().Unix())
for i:=0; i<10; i++ {
fmt.Print(rand.Intn(10), " ")
}
}
或者我们可以使用rand.NewSource()
func checkSumBuilder() (string, string, string){
r := rand.New(rand.NewSource(time.Now().UnixNano()))
num := r.Intn(128)
}
6. Intn函数
func Intn(n int) int
生成 [0,n)区间的一个随机数(注意:不包括n)
更多详情查看math/rand官网
7. 生成指定位数的随机数(以生成8位为例)
package main
import (
"fmt"
"math/rand"
)
func main() {
s := fmt.Sprintf("%08v", rand.New(rand.NewSource(time.Now().UnixNano())).Int63n(100000000))
fmt.Println(s)
}
8. 真随机数
如果我们的应用对安全性要求比较高,需要使用真随机数的话,那么可以使用 crypto/rand 包中的方法,这样生成的每次都是不同的随机数.
package main
import (
"crypto/rand"
"fmt"
"math/big"
)
func main() {
// 生成 10 个 [0, 128) 范围的真随机数。
for i := 0; i < 10; i++ {
result, _ := rand.Int(rand.Reader, big.NewInt(128))
fmt.Println(result)
}
}