Go 语言生成随机数的两种方式:math/rand 与 crypto/rand

陈默
陈默
发布时间:2026-10-15 | 5人浏览过
原创

在Go开发中,根据业务场景对安全性的不同要求,通常采用两种随机数生成方案:math/rand 生成的伪随机数和 crypto/rand 生成的真随机数。本文详解两者的区别、使用方法及自定义字符串生成实现。

Go 语言随机数核心区别

Go 语言标准库提供了两套独立的随机数机制,其根本区别在于来源与适用场景:

  • math/rand:伪随机数生成器。基于算法确定性地生成数字序列,性能高但可预测。适用于游戏逻辑、数据模拟等非安全敏感场景。
  • crypto/rand:真随机数生成器。直接从操作系统获取熵源(如硬件中断),符合 NIST 标准,具有不可预测性但性能较低。适用于密钥生成、令牌验证等安全敏感场景。

第1步:使用 math/rand 生成伪随机数

由于伪随机数算法依赖于初始状态(Seed),若不设置种子,每次程序启动生成的“随机”序列将完全一致。为确保每次运行结果不同,需使用时间戳作为种子。

1.1 基础随机整数生成

通过 rand.Seed 初始化随机种子,随后调用 rand.Intn 获取指定范围内的整数。注意:该示例使用了较早期的 API 调用方式。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	// 1. 设置随机数种子,基于当前时间纳秒
	rand.Seed(time.Now().UnixNano())
	
	// 2. 生成 [0, 100) 之间的随机整数
	fmt.Println(rand.Intn(100))
}

1.2 自定义随机字符串生成

在实际开发中,常需生成由特定字符集组成的随机字符串(如验证码)。以下代码演示了如何混合数字、大小写字母生成随机串。

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main() {
	// 生成6位纯数字随机码
	fmt.Println(randomString(6, 0))
}

// size: 随机字符串长度
// kind: 0=纯数字, 1=小写字母, 2=大写字母, 3=混合
func randomString(size int, kind int) string {
	ikind := kind
	// 定义字符集范围:[数量, ASCII起始值]
	kinds := [][]int{
		{10, 48}, // 0-9 (ASCII 48)
		{26, 97}, // a-z (ASCII 97)
		{26, 65}, // A-Z (ASCII 65)
	}
	
	rsbytes := make([]byte, size)
	
	// 设置随机种子
	rand.Seed(time.Now().UnixNano())
	
	for i := 0; i < size; i++ {
		isAll := kind > 2 || kind < 0
		if isAll {
			// 混合模式:每轮随机选择一种字符类型
			ikind = rand.Intn(3)
		}
		
		scope := kinds[ikind][0]
		base := kinds[ikind][1]
		
		// 计算字符并转换
		rsbytes[i] = uint8(base + rand.Intn(scope))
	}
	
	return string(rsbytes)
}

第2步:使用 crypto/rand 生成真随机数

当应用场景涉及安全性时,应使用 crypto/rand。该包从系统熵池读取数据,无法被预测,但 I/O 开销较大,不适合高频调用场景。

2.1 基本真随机数获取

通过 binary.Read 将 crypto/rand.Reader 的字节流转换为整数类型。

package main

import (
	"crypto/rand"
	"encoding/binary"
	"fmt"
)

func main() {
	var n int32
	// 从 crypto/rand 读取 4 字节数据填充到 n
	error := binary.Read(rand.Reader, binary.LittleEndian, &n)
	if error != nil {
		fmt.Printf("Error reading from rand: %v\n", error)
		return
	}
	fmt.Println(n)
}

注意事项与最佳实践

  • 版本差异提醒:在 Go 1.20 及以上版本中,math/rand 的默认源已改为全局默认值,不再强制要求手动调用 rand.Seed,因为全局源已在程序启动时自动初始化。但在旧版本或需要显式控制时,上述 rand.Seed 方法依然有效且必要。
  • 性能权衡:除非业务明确要求不可预测性,否则优先使用 math/rand,因其速度比 crypto/rand 快数十倍。
  • 错误处理:在使用 crypto/rand 进行二进制读取时,务必检查返回的错误,确保数据正确解析。

以上就是 Go 语言随机数生成方式的详细内容,更多关于 Golang 数学库与加密模块的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表