
本文详解 go 语言中使用 math/rand 包生成随机数的完整流程,涵盖种子初始化、随机数生成器创建、常用方法调用,并修正常见错误(如未使用导入包、未定义变量、缺乏种子导致重复结果等)。
在 Go 中生成随机数,不能直接调用类似 Rand() 的全局函数(该写法既不存在也不符合 Go 的设计哲学),而必须显式创建并使用一个 *rand.Rand 实例。这是初学者常踩的坑——例如原代码中 float64 := (milesdriven * Rand) 不仅语法错误(Rand 未定义),还混淆了类型声明与变量赋值,且未初始化随机源。
✅ 正确做法分为三步:
- 导入必要包:math/rand 用于随机逻辑,time 用于获取纳秒级时间作为种子;
- 初始化随机源:用 rand.NewSource(seed) 创建确定性种子源(推荐用 time.Now().UnixNano() 避免重复);
- 构造随机数生成器:通过 rand.New(source) 得到可安全并发使用的 *rand.Rand 实例。
以下是可直接运行的完整示例:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// ✅ 步骤1&2:用当前时间纳秒作为种子,创建随机源
seed := time.Now().UnixNano()
r := rand.New(rand.NewSource(seed))
// ✅ 步骤3:调用各类随机方法
fmt.Printf("Float64 [0.0, 1.0): %.4f\n", r.Float64())
fmt.Printf("Intn(100) [0, 100): %d\n", r.Intn(100))
fmt.Printf("Int31n(50) [0, 50): %d\n", r.Int31n(50))
fmt.Printf("Float32: %.4f\n", r.Float32())
// ? 生成指定范围的随机整数:[min, max)
min, max := 10, 50
randomInt := min + r.Intn(max-min)
fmt.Printf("Random int in [%d, %d): %d\n", min, max, randomInt)
}⚠️ 关键注意事项:
- ❌ 不要省略种子初始化:若始终使用 rand.Seed()(已弃用)或固定种子(如 rand.NewSource(42)),每次运行结果将完全相同;
- ❌ 不要混用 rand.* 全局函数(如 rand.Intn())与自定义 *rand.Rand 实例——它们共享同一全局状态,易引发竞态且不可预测;
- ✅ 推荐始终使用 rand.New(...) 创建独立实例,尤其在并发场景下更安全、更可控;
- ? 若需复现结果(如测试),可显式传入固定种子(如 rand.NewSource(12345)),但生产环境务必用 time.Now().UnixNano()。
? 小技巧:为简化日常开发,可封装一个带时间种子的初始化函数:
func newRand() *rand.Rand {
return rand.New(rand.NewSource(time.Now().UnixNano()))
}这样即可在任意位置快速获得隔离、高质量的随机数生成器。掌握这一模式,你就能在 Go 中稳定、可靠、高效地生成各类随机数值了。










