
本文详解 go 语言中安全、可重现地生成随机数的方法,涵盖 `math/rand` 包的核心用法、种子设置、常见类型(整数/浮点数/范围随机值)及关键注意事项,帮助开发者避免“undefined rand”和“imported and not used”等典型错误。
在 Go 中,生成随机数需显式使用 math/rand 包——它不提供全局函数(如 rand.Int()),也不自动初始化种子。初学者常因直接调用未定义的 Rand 或忽略种子导致编译错误(如 undefined: Rand)或程序每次运行输出相同序列(如始终为 0)。正确做法是:*创建独立的 `rand.Rand` 实例,并传入带时间戳的种子源**。
以下是最小可用示例:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// ✅ 正确:使用当前纳秒时间作为种子,确保每次运行结果不同
seed := time.Now().UnixNano()
r := rand.New(rand.NewSource(seed))
// 生成 [0.0, 1.0) 区间的 float64 随机数
fmt.Printf("Float64: %.4f\n", r.Float64())
// 生成 int64 随机数(最大值为 math.MaxInt64)
fmt.Printf("Int64: %d\n", r.Int64())
// 生成 [0, 100) 的 int 随机数(常用范围控制)
fmt.Printf("Intn(100): %d\n", r.Intn(100))
// 生成 [5, 15] 的 int 随机数(闭区间)
n := r.Intn(11) + 5 // Intn(11) → [0,11), +5 → [5,16) → 即 [5,15]
fmt.Printf("Int in [5,15]: %d\n", n)
}⚠️ 关键注意事项:不要省略 time 导入:UnixNano() 是最常用的种子来源,缺失会导致 seed 恒为 0,所有随机数序列完全相同;避免使用 rand.Seed() 和全局函数(已弃用):Go 1.20+ 中 rand.Seed() 和 rand.Int() 等全局函数已被标记为废弃,因其线程不安全且不可控;慎用 rand.Int():它返回 int 类型,但 int 在不同架构下长度不同(32/64 位),推荐明确使用 Int32()、Int64() 或 Intn(n);测试时需固定种子:单元测试中应传入固定种子(如 rand.NewSource(42)),保证结果可重现;并发安全:每个 goroutine 应使用独立的 *rand.Rand 实例,或使用 sync.Mutex 保护共享实例。
此外,若需密码学安全的随机数(如生成密钥、token),请改用 crypto/rand 包,其不依赖种子且由操作系统熵池提供真随机性:
import "crypto/rand"
func cryptoRandom() {
b := make([]byte, 8)
_, _ = rand.Read(b) // 忽略错误仅作示意;实际需检查 err
fmt.Printf("Crypto random bytes: %x\n", b)
}总结:Go 的随机数机制强调显式性与可控性——你必须主动创建 *rand.Rand、显式设置种子、并选择合适的方法。遵循此模式,即可写出健壮、可测试、跨平台一致的随机逻辑。










