rand.intn() 每次返回相同数是因为未设置种子,默认使用固定种子(如1),这是设计特性而非bug;正确做法是用rand.new(rand.newsource(time.now().unixnano()))创建独立实例,注意导入time包,测试时可用固定种子如42;生成[min,max]闭区间整数应写为min + r.intn(max-min+1)。

rand.Intn() 为什么每次运行都返回一样的数?
因为没设种子,math/rand 默认用固定种子(比如 1),伪随机序列完全可复现——这不是 bug,是设计如此。你看到的“总一样”,恰恰说明它工作正常,只是你忘了初始化。
- Go 1.20+ 已废弃
rand.Seed(),别再用;正确做法是显式创建独立实例:rand.New(rand.NewSource(time.Now().UnixNano())) - 漏掉
"time"导入会导致time.Now().UnixNano()恒为0,种子永远是0,结果还是固定 - 若在测试里需要可复现结果,就用固定种子,比如
rand.NewSource(42),而不是依赖系统时间
如何生成 [min, max] 闭区间的整数?
rand.Intn(n) 只给 [0, n),想得 [5, 15] 这种常见范围,得手动偏移缩放:先算长度 max - min + 1,再加 min。
- 错误写法:
r.Intn(15) + 5→ 实际范围是[5, 19](因为Intn(15)是[0,15)) - 正确写法:
min + r.Intn(max-min+1),例如骰子点数1 + r.Intn(6) - 注意边界检查:
max 或 <code>max-min+1 会 panic,用户输入做参数时务必校验
并发环境下能共用一个 *rand.Rand 实例吗?
可以,但不推荐高频场景下这么做——它内部加了 mutex,goroutine 一多就会排队等锁,压测时容易看到 runtime.futex 占比飙升。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 短生命周期 goroutine(如 HTTP handler):直接
rand.New(rand.NewSource(time.Now().UnixNano()))更简单、无状态污染 - 长周期、高吞吐 goroutine(如后台 worker):考虑用
sync.Pool复用,但 Pool 的New函数不能每次都调用time.Now(),否则失去复用意义 - 绝对不要在多个 goroutine 里反复调用同一个实例的
Seed()(已废弃)或重置源,会引发竞态
什么时候该换 crypto/rand?
只在生成密钥、JWT token、密码 salt、AES IV 这类**不可预测、不可复现、抗攻击**的场景才必须换;游戏抽卡、打乱切片、mock 数据这些,math/rand 完全够用,且快得多。
-
crypto/rand在低熵环境(如 CI 容器、某些嵌入式系统)可能阻塞,甚至超时失败 - 它没有
Intn()这种便利方法,要自己读字节、转整数、再取模——代码啰嗦,还容易因字节截断引入偏差 - 别被名字误导:“crypto” 不等于“更高级”,而是“更重、更慢、更专一”
真正容易被忽略的不是怎么写,而是什么时候不该用全局函数、什么时候必须隔离实例、以及为什么固定种子在测试里不是偷懒而是必要控制。写完记得检查三件事:有没有 time 导入、Intn 的参数是否非零、并发路径是否共享了同一把锁。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










