• 首页
  • go
  • go 语言实践:随机数生成

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

没有问题,上面的效果是我们想要的结果.

出自:go 语言实践:随机数生成

回到顶部