go 语言实践:随机数生成
文章目录
go语言中的随机数
math/rand包操作随机数,
rand.Seed(seedNum)方法设定种子值,
rand.Intn(n)获取一个小于n的随机数,[ 同一个种子值,生成的随机数是确定的 ]
所以go语言中的随机数取决于种子的随机性,
一般情况下可以采用系统时间的毫秒数作为种子值.
当种子值相同时
package main
import (
"fmt"
"math/rand"
)
func main() {
rand.Seed(888)
//获取8个小于1000的随机数
for i := 0; i < 8; i++ {
fmt.Printf("%d ", rand.Intn(1000))
}
fmt.Println("--------")
//生成随机数
rand.Seed(888)
for i := 0; i < 8; i++ {
fmt.Printf("%d ", rand.Intn(1000))
}
fmt.Println("--------")
}
结果随机数也相同:
294 303 749 471 664 832 888 221 --------
294 303 749 471 664 832 888 221 --------
当用当前时间作为随机种子的时候
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
var seedNum int64
//用系统时间作为随机数种子
seedNum = time.Now().UnixNano()
rand.Seed(seedNum)
for i := 0; i < 8; i++ {
fmt.Printf("%d ", rand.Intn(1000))
}
fmt.Println("--------")
//系统时间延迟1秒钟,以获得新的时间
time.Sleep(time.Second)
seedNum = time.Now().UnixNano()
//延迟1秒后生成随机数
rand.Seed(seedNum)
for i := 0; i < 8; i++ {
fmt.Printf("%d ", rand.Intn(1000))
}
fmt.Println("--------")
}
先用系统当前时间作为随机种子,
然后延迟1秒,再获取当前时间作为随机种子
结果如下:
0 528 627 162 63 489 324 27 --------
623 454 974 844 923 684 460 184 --------
如果每次生成随机数都用当前时间作为随机种子应该就没问题吧?
我们测试一下这种情况,比如连续生成8个随机验证码
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
for i := 0; i < 10; i++ {
//当前时间戳设置为随机种子
rand.Seed(time.Now().Unix())
//存放验证码的数组切片
bytes := make([]byte, 8)
for i := 0; i < 8; i++ {
//c的ascii码值:65~90为26个大写英文字母,97~122号为26个小写英文字母
//其余为一些标点符号、运算符号等
//我们要获取8个大写字母的验证码
b := rand.Intn(26) + 65
bytes[i] = byte(b)
}
fmt.Println(string(bytes))
}
}
上面 rand.Seed 设置随机种子的时候是在 for 循环内部;
每次循环都获取当前时间戳来作为随机种子,然后随机一个小于26的数字, + 65 变成大写字母 ascii码值.
我们查看结果:
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
BBIKFUNZ
你测试上面代码时,可能得到的随机结果不是上面值,但是能确定的是,出来的随机数全部一样,
也许循环太快,可能随机种子相同了,但是你随机生成1万个验证码依然是一样的,感兴趣的同学可以试一下.
如果你碰到这样的业务逻辑,用上面的方式来生成随机数,就直接跳进坑里了.
这种情况怎么办呢,我们可以直接用循环变量来作为随机种子,
如下代码:
package main
import (
"fmt"
"math/rand"
)
func main() {
for i := 0; i < 10; i++ {
//当前循环变量作为随机种子
rand.Seed(int64(i))
//存放验证码的数组切片
bytes := make([]byte, 8)
for i := 0; i < 8; i++ {
//c的ascii码值:65~90为26个大写英文字母,97~122号为26个小写英文字母
//其余为一些标点符号、运算符号等
//我们要获取8个大写字母的验证码
b := rand.Intn(26) + 65
bytes[i] = byte(b)
}
fmt.Println(string(bytes))
}
}
我们直接查看运行结果:
CUBYHIZZ
XVLBZGBA
IMMOAGMS
MTUOPREV
NOFDHZOF
QMZSXIIF
QFWAGJGC
GOVHGGYY
AGZGUCHJ
ZSKNPCTQ
没有问题,上面的效果是我们想要的结果.