1、math/rand
2、crypto/rand
1、math/rand随机数从资源生成。包水平的函数都使用的默认的公共资源。
该资源会在程序每次运行时都产生确定的序列。如果需要每次运行产生不同的序列,应使用Seed函数进行初始化。默认资源可以安全的用于多go程并发。
关于种子seed
程序启动的时候,种子的初始值是一样的,也就是说随机数是一样的,什么意思呢?
package main
import (
"fmt"
"math/rand"
)
func main(){
data := rand.Int63n(100)
fmt.Println(data)
}
每次运行go run main.go
打印的都是 10
如果我们播放种子
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
rand.Seed(time.Now().Unix()) // unix 时间戳,秒
data := rand.Int63n(100)
fmt.Println(data)
}
这样每次执行go run main.go
打印的结果就不一样,但是,根据随机数的特性,如果两次执行的时间戳是在同一秒,那么打印的结果是相同的。
以上的随机数相同的情况是发生在程序启动的时候,如果程序启动后,每次生成随机数会怎样呢?
package main
import (
"fmt"
"math/rand"
)
func main(){
for i := 0; i<5; i++ {
data := rand.Int63n(100)
fmt.Println(data)
}
}
运行 go run main.go
打印
10
51
21
51
37再次运行 go run main.go
打印
10
51
21
51
37
可见每次启动的结果是一样的;但是程序启动后,每次的随机数都不尽相同,是随机的。
如果再加上种子呢?
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
for i := 0; i<5; i++ {
rand.Seed(time.Now().Unix()) // unix 时间戳,秒
data := rand.Int63n(100)
fmt.Println(data)
}
}
运行 go run main.go
打印
86
86
86
86
86再次运行 go run main.go
打印
72
72
72
72
72
每次启动程序,因为种子不一样,所以随机数不一样;但是程序启动后,每次也都是播放种子,秒级时间戳,如果时间戳一样,就导致种子一样,生成的随机数就一样,所以五次的随机数是一样的。
通过上面的例子。可以知道,播放种子不是必须的,除非要求每次启动程序的时候随机数不一样。
并且,要设置种子的情况下,应该放在整个程序启动的时候,而且只需要设置一次即可。修改上面的例子:
package main
import (
"fmt"
"math/rand"
"time"
)
func main(){
rand.Seed(time.Now().UnixNano()) // 纳秒时间戳
for i := 0; i<5; i++ {
data := rand.Int63n(100)
fmt.Println(data)
}
}
运行 go run main.go
打印
3
49
46
83
25再次运行 go run main.go
打印
39
3
14
42
65
这次就是理想的结果了。使用纳秒时间戳基本就没问题了,因为我们的程序几乎不会在1纳秒时间内多次启动的。
下面来讲讲rand包的具体用法
rand 包提供了两块的内容,一块是基于 Rand 结构体及其方法;另一块是基于 Rand 结构体再封装的可直接调用的方法 rand.xxx,查看源码就知道它们是同样的功能。
所以,生成随机数有两种方式
rander := rand.New(rand.NewSource(time.Now().UnixNano()))
n1 := rander.Intn(100)
rand.Seed(time.Now().UnixNano())
n2 := rand.Intn(100)
使用第一种方法,将 rander 作为包的全局变量,这样就只会设置一次种子。
var Rander = rand.New(rand.NewSource(time.Now().UnixNano()))
随机整数
func (r *Rand) Int() int
func (r *Rand) Int31() int32
func (r *Rand) Int63() int64
func (r *Rand) Uint32() uint32
func (r *Rand) Uint64() uint64
func (r *Rand) Intn(n int) int
func (r *Rand) Int31n(n int32) int32
func (r *Rand) Int63n(n int64) int64
Int, Int31, Int63 生成的数都太大,一般使用 Intn, Int31n, Int63n。得到的范围 [0, n),想要得到 [0, n],就要使用 Intn(n + 1),想要得到 [10, 100] 的随机数,就要使用 Intn(91) + 10。
随机浮点数
func (r *Rand) Float32() float32
func (r *Rand) Float64() float64
得到 [0, 1) 之间的浮点数,32单精度,64双精度。
基于正态分布的随机浮点数
func (r *Rand) NormFloat64() float64
基于指数分布的随机浮点数
func (r *Rand) ExpFloat64() float64
随机序列
func (r *Rand) Perm(n int) []int
返回一个有n个元素的,[0,n)范围内整数的伪随机排列的切片。
Rander.Perm(10) // [1 8 0 4 7 6 3 2 9 5]
总结:
package main
import (
"fmt"
"math/rand"
"strings"
"time"
)
func main() {
s := RandString(10)
fmt.Println(s)
}
var Rander = rand.New(rand.NewSource(time.Now().UnixNano()))
const letterString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const numLetterString = "0123456789"
// 随机生成字符串
func RandStr(n int, letter string) string {
str := []byte(letter)
res := ""
for i := 0; i < n; i++ {
res += fmt.Sprintf("%c", str[Rander.Intn(strings.Count(letter, "") - 1)])
}
return res
}
func RandNumStr(n int) string {
return RandStr(n, numLetterString)
}
func RandString(n int) string {
return RandStr(n, letterString)
}
func RandOrder(n int) string {
return time.Now().Format("20060102150405") + RandNumStr(n)
}
// 包含min, max
func RandNum(min , max int) int {
return Rander.Intn(max - min + 1) + min
}
2、crypto/rand
实现了用于加解密的更安全的随机数生成器。
变量 var Reader io.Reader
是一个全局、共享的密码用强随机生成器。在Unix类型系统中,会从/dev/urandom读取;而windows中会调用RtlGenRandom API。
提供的方法
1、返回一个基于[0, max)的随机数
// Int returns a uniform random value in [0, max). It panics if max <= 0.
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error)
示例
r, err := rand.Int(rand.Reader, big.NewInt(100))
fmt.Println(r.Int64(), err)
2、根据指定的位数bits,返回一个数,大概率是素数,(不知道这个函数是干嘛用的)
// Prime returns a number, p, of the given size, such that p is prime
// with high probability.
// Prime will return error for any error returned by rand.Read or if bits < 2.
func Prime(rand io.Reader, bits int) (p *big.Int, err error)
示例
p, err := rand.Prime(rand.Reader, 8)
fmt.Println(p.Int64(), err)
8个二进制位的最大值为255,此处会随机返回小于255的素数。
3、生成随机的二进制序列
// Read is a helper function that calls Reader.Read using io.ReadFull.
// On return, n == len(b) if and only if err == nil.
func Read(b []byte) (n int, err error) {
return io.ReadFull(Reader, b)
}
比如,随机生成16个字节的数据
var b [16]byte
n, err := rand.Read(b[:])
fmt.Println(n, err)
fmt.Println(b)
返回值
16 <nil>
[94 184 113 36 224 18 239 52 69 242 14 84 174 113 125 15]
我们可以将其转换成16进制数,也就是32位
buf := make([]byte, 32)
hex.Encode(buf, b[:])
fmt.Println(string(buf))
得到
5eb87124e012ef3445f20e54ae717d0f
通过这个方法可以生成随机的字符串。
到此这篇关于golang中随机数rand的使用的文章就介绍到这了,更多相关golang随机数rand内容请搜索易知道(ezd.cc)以前的文章或继续浏览下面的相关文章希望大家以后多多支持易知道(ezd.cc)!