无需打开直接搜索微信:本司针对手游进行,选择我们的四大理由: ...
2025-08-14 0
如果把计算机内存比作一个大型仓库,那里面有两种核心存储区域,就像超市的 “货架” 和 “自助储物柜”:
Rust 变量的存储遵循一个简单规则:基本类型放栈上,复杂类型放堆上(栈上存 “钥匙”)。就像超市里小零食放货架(栈),大行李箱放储物柜(堆),货架上贴标签注明柜子位置。
基本类型(如整数、布尔值、字符等)大小固定,编译时就能确定,所以直接存放在栈上,存取速度极快。
fn main() {
// 整数类型i32:4字节,存栈上
let age: i32 = 25;
// 布尔类型:1字节,存栈上
let is_student: bool = true;
// 字符类型char:4字节,存栈上
let initial: char = 'R';
println!("年龄:{},是否学生:{},首字母:{}", age, is_student, initial);
}
编译运行步骤:
rustc stack_basic.rs
内存解析:
栈上像货架一样依次摆放:age(25)→ is_student(true)→ initial('R'),程序结束后自动从栈顶依次清理,无需手动管理。就像超市下班前,货架上的商品按摆放顺序依次收走。
复杂类型(如String、Vec)大小不确定,需要动态变化,所以数据存放在堆上,而栈上只保存 “管理信息”(指针、长度、容量),就像储物柜的钥匙上刻着 “柜子位置、物品数量、柜子大小”。
fn main() {
// String数据存堆上,栈上存元数据:指针(地址)、长度(5)、容量(5)
let name = String::from("Rust");
println!("字符串:{},长度:{},容量:{}", name, name.len(), name.capacity());
// 打印栈上元数据的地址(证明元数据在栈上)
println!("栈上元数据地址:{:p}", &name);
}
编译运行步骤:
内存解析:
就像钥匙上写着 “3 号柜,4 件物品,能装 4 件”,柜子里放着实际物品。
fn main() {
let s1 = String::from("Hello");
println!("s1栈地址:{:p},堆数据:{}", &s1, s1);
let s2 = s1; // 所有权转移:s2获得栈上元数据,s1失效
// println!("s1还能用吗?{}", s1); // 报错:s1已无所有权
println!("s2栈地址:{:p},堆数据:{}", &s2, s2);
}
运行结果:
s1栈地址:0x7ffd9a0b9a70,堆数据:Hello
s2栈地址:0x7ffd9a0b9a90,堆数据:Hello
内存解析:
所有权转移时,栈上的 “钥匙” 被复制给 s2,但堆上的 “物品”(Hello)并未复制。这就像你把储物柜钥匙给了朋友,朋友成了新主人,你手里的钥匙失效了(避免 “同一物品被两人同时管理” 的混乱)。
引用(&)就像物品的 “临时通行证”,只允许查看或使用,不转移所有权,栈上只存指向目标的地址。
fn print_length(s: &String) {
// s是引用,栈上存指向String的地址
println!("字符串长度:{},引用地址:{:p}", s.len(), s);
}
fn main() {
let s = String::from("Rust Programming");
println!("原字符串地址:{:p}", &s);
print_length(&s); // 传递引用,类似借出通行证
print_length(&s); // 还能再借,所有权仍归s
}
运行结果:
原字符串地址:0x7ffd9b9c8a70
字符串长度:16,引用地址:0x7ffd9b9c8a70
字符串长度:16,引用地址:0x7ffd9b9c8a70
内存解析:
引用在栈上存储的是目标变量的地址(就像通行证上写着物品位置),函数调用时传递引用不会复制堆数据,既高效又安全。
Vec(动态数组)和String类似,堆上存实际元素,栈上存元数据。
fn main() {
let mut numbers = vec![1, 2, 3]; // Vec<i32>
println!("初始元素:{:?},长度:{},容量:{}", numbers, numbers.len(), numbers.capacity());
numbers.push(4); // 追加元素,若容量不足会扩容
println!("追加后:{:?},长度:{},容量:{}", numbers, numbers.len(), numbers.capacity());
}
运行结果:
初始元素:[1, 2, 3],长度:3,容量:3
追加后:[1, 2, 3, 4],长度:4,容量:6 // 容量通常翻倍扩容
内存解析:
Vec栈上存 “指针(堆地址)、长度(元素数)、容量(最大元素数)”,堆上存连续的元素。扩容时会在堆上分配更大空间,复制旧元素,释放旧空间(类似换更大的储物柜)。
// 危险!递归过深导致栈溢出
fn recursive_stack(count: i32) {
let big_array = [0; 1024]; // 每次递归在栈上分配1KB数组
if count < 10000 {
recursive_stack(count + 1);
}
}
fn main() {
recursive_stack(0); // 运行会崩溃:栈空间不足
}
避坑:栈空间有限(通常几 MB),避免在栈上存大型数组或过深递归,大数据用堆存储(如Vec)。
fn dangle() -> &String {
let s = String::from("危险");
&s // 错误!s在函数结束时被释放,返回的引用指向无效内存
}
fn main() {
// let reference = dangle(); // 编译报错,阻止悬垂引用
}
避坑:Rust 编译器会阻止返回指向栈上临时变量的引用,确保引用始终指向有效内存。
访问 rust-lang.org 下载rustup,按提示安装(包含rustc编译器和cargo工具)。
用记事本或 VS Code 创建.rs文件(如memory_demo.rs)。
rustc memory_demo.rs # 生成可执行文件
本文通过仓库货架(栈)与储物柜(堆)的现实类比,通俗解析了 Rust 变量的内存存储机制,结合多个完整代码案例演示了基本类型栈存储、复杂类型堆存储、所有权转移及引用的内存变化,详细说明编译运行步骤,帮助读者轻松掌握 Rust 内存管理的核心逻辑。
#Rust 内存管理 #栈与堆 #所有权 #变量存储 #Rust 基础
相关文章
您好:这款游戏可以开挂,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到-人的牌一样。所以很多小伙伴就怀疑这...
2025-08-14 0
今天给各位分享微乐保皇小程序有挂吗的知识,其中也会对微乐保皇有没有挂进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!多乐保皇两个...
2025-08-14 0
发表评论