首页 抖音快讯文章正文

rust 揭秘随机数代码的内存魔法:栈和堆的 "幕后分工"

抖音快讯 2025年08月24日 14:35 2 admin
rust 揭秘随机数代码的内存魔法:栈和堆的 "幕后分工"

rust 揭秘随机数代码的内存魔法:栈和堆的 "幕后分工"

像超市储物柜一样简单:代码里的内存怎么存?

一、先复习内存 “两兄弟”:栈和堆

在聊代码前,先给内存俩兄弟做个自我介绍:



  • :像超市的临时储物柜,存取快、容量小,必须 “先进后出”(取东西得先拿最后放的)。适合存 “临时小数据”,比如数字、固定大小的变量。
  • :像小区的自助快递柜,空间大、存取慢,存东西时要先找空位再记地址。适合存 “动态大数据”,比如字符串、可变长度的数组。



简单说:栈是 “快闪便利店”,堆是 “大型仓储超市”~

二、逐行拆解代码:栈和堆的 “工作日记”

我们把代码拆成 “时间线”,看看每一步栈和堆都在忙啥:



rust

use std::time::SystemTime;  // ① 引入标准库模块fn main() {  // ② 进入main函数,栈开始“营业”    // 步骤1:获取系统时间    let now = SystemTime::now()  // ③ 调用获取当前时间的方法        .duration_since(SystemTime::UNIX_EPOCH)  // ④ 计算时间差        .expect("时间机器故障啦!");  // ⑤ 处理可能的错误    let nanos = now.as_nanos() as u64;  // ⑥ 转换时间单位为纳秒    // 步骤2:生成0-99的随机数    let random_num = nanos % 100;  // ⑦ 计算随机数    println!("系统时间搓的随机数:{}", random_num);  // ⑧ 打印结果}  // ⑨ 离开main函数,栈“下班清场”

第①步:引入模块use std::time::SystemTime;

  • 内存动作:这一步只是 “告诉编译器去哪找工具”,不占用栈或堆内存。
  • 类比:就像你告诉朋友 “超市储物柜在二楼”,光说不占柜子空间~

第②步:进入main函数

  • 内存动作:栈为 main 函数创建一个 “活动记录”(也叫栈帧),用来存放函数内的局部变量。
  • 类比:超市储物柜系统启动,准备接收顾客的存物请求~

第③-⑤步:获取系统时间并处理错误

rust

let now = SystemTime::now()    .duration_since(SystemTime::UNIX_EPOCH)    .expect("时间机器故障啦!");



  • 内存细节:SystemTime::now() 返回一个 SystemTime 类型的值,这是个 “轻量级结构体”(类似小纸条),直接存在栈上。duration_since(...) 方法计算从 “UNIX 纪元” 到现在的时间差,返回 Result<Duration, SystemTimeError> 类型(结果或错误),也存在栈上。expect(...) 方法如果成功,会提取 Result 里的 Duration 类型值,赋值给 now——Duration 结构体里存着秒数和纳秒数,都是固定大小的数字,继续存在栈上。
  • 为什么不用堆?:这些类型大小固定(编译时就知道占多少内存),栈能轻松放下,没必要麻烦堆。
  • 类比:你在储物柜存了个小钱包(now),钱包里的身份证(秒数)和零钱(纳秒数)都固定大小,直接塞柜子里~

第⑥步:转换时间单位let nanos = now.as_nanos() as u64;

  • 内存细节:now.as_nanos() 把 Duration 转成 u128 类型的纳秒总数(非常大的数字),临时存放在栈上的 “表达式计算区”。as u64 把 u128 转成 u64 类型(64 位无符号整数),赋值给 nanos——nanos 是局部变量,存在栈上。
  • 栈的动作:新增一个 u64 大小的空间(8 字节)给 nanos,存放转换后的纳秒数。
  • 类比:你把钱包里的零钱总数(比如 “1234567 纳秒”)写在一张小纸条(nanos)上,塞进同一个储物柜~

第⑦步:计算随机数let random_num = nanos % 100;

  • 内存细节:nanos % 100 是算术运算,结果是 u64 类型(0-99 之间的数字),临时存栈上的 “计算区”。结果赋值给 random_num,random_num 是 u64 类型局部变量,存在栈上。
  • 栈的动作:再新增一个 8 字节空间给 random_num,存放最终的随机数。
  • 类比:你用计算器算 “1234567 ÷ 100 的余数”,结果 “67” 写在另一张纸条(random_num)上,也塞进储物柜~

第⑧步:打印结果println!(...)

  • 内存细节:字符串字面量 "系统时间搓的随机数:{}" 是静态字符串,编译时就存在 “静态内存区”(既不是栈也不是堆)。println! 宏把 random_num 的值格式化成字符串,临时生成的格式化字符串可能在栈上分配(因为长度短且固定)。打印完成后,临时字符串占用的栈空间会被释放。
  • 为什么不用堆?:格式化后的字符串很短(比如 “系统时间搓的随机数:67”),栈的临时空间足够放下,堆表示 “没我事,歇会儿~”。
  • 类比:你把纸条上的数字(67)抄在便签上递给收银员,便签用完就扔,不用存快递柜~

第⑨步:离开main函数

  • 内存动作:main 函数的栈帧被 “销毁”,栈上的 now、nanos、random_num 等局部变量占用的空间全部释放,栈恢复到函数调用前的状态。
  • 类比:你取完所有东西离开,储物柜自动清空,下一个人可以继续用~

三、总结:这段代码里栈和堆的 “工作量”

内存区域

工作内容

类比

存放 now(Duration 结构体)、nanos(u64)、random_num(u64),以及函数调用的临时计算结果

临时储物柜,存放小物品和计算过程中的纸条

全程 “摸鱼”,没有任何数据存放在堆上

大型仓储超市,这次交易太小,没用到它

静态区

存放字符串字面量(如打印的提示文本)

超市的固定广告牌,一直存在不消失

为什么这段代码 “不麻烦堆”?

因为所有数据都是固定大小的基本类型(u64、Duration 结构体)和编译时已知的字符串,栈的 “小空间 + 快速度” 完全能搞定。只有当我们需要存动态大小的数据(比如可变长度的字符串、数组)时,堆才会 “被迫营业”~



就像你买瓶水用口袋(栈)装就行,没必要开卡车(堆)来运~

发表评论

泰日号Copyright Your WebSite.Some Rights Reserved. 网站地图 备案号:川ICP备66666666号 Z-BlogPHP强力驱动