目标搞懂 let、let mut、const、static、shadowing以及它们背后的设计哲学。一、核心概念变量默认不可变Rust 和其他语言最大的不同变量默认不可变。fnmain(){letx5;x6;// ❌ 编译错误cannot assign twice to immutable variable}想改就得加 mutfnmain(){letmutx5;x6;// ✅println!({},x);// 6}为什么这样设计 因为大部分 bug 来自“意料之外的修改”。默认不可变让编译器帮你挡住这类问题需要改时再显式声明意图清晰。常量 constconstMAX_POINTS:u32100_000;规则· 必须标注类型· 值必须是编译期可计算的常量表达式· 命名惯例全大写加下划线· 可以定义在任意作用域包括全局· 不能用 mut静态变量 staticstaticGREETING:strHello;staticmutCOUNTER:i320;// 可变的 static 是 unsafe 的先别碰const 和 static 的区别· const 在编译期被“内联”到使用处相当于文本替换· static 有固定内存地址全局唯一· 大多数场景用 const 就够变量遮蔽shadowing可以用同一个名字重新 let新变量会“遮蔽”旧变量fnmain(){letx5;letxx1;// 新的 x值为 6letxx*2;// 又一个新的 x值为 12println!({},x);// 12}遮蔽 vs mut 的关键区别· mut 是同一个变量类型不能变· 遮蔽是新变量可以换类型letspaces ;// strletspacesspaces.len();// usize类型变了合法而用 mut 就不行letmutspaces ;spacesspaces.len();// ❌ 类型不匹配二、多元化练习题含答案与解读 练习 1基础让代码编译通过fnmain(){letx10;x20;println!({},x);}参考答案fnmain(){letmutx10;x20;println!({},x);// 20}解读只需把 let x 改成 let mut x。编译器报错信息会明确提示 “help: consider changing this to be mutable”。 练习 2基础常量定义要求定义一个常量 PI值为 3.14159类型 f64并打印它。参考答案constPI:f643.14159;fnmain(){println!(PI {},PI);}解读常量必须标类型命名全大写。常量可以定义在 main 外面全局可用。 练习 3理解 shadowing预测输出fnmain(){letx1;letxx1;{letxx*10;println!(内层: {},x);}println!(外层: {},x);}参考答案内层: 20 外层: 2解读花括号 {} 创建了一个新的作用域。内层的 let x x * 10 只在内层生效出了花括号就回到外层的 x 2。这就是遮蔽加作用域的组合效果。 练习 4遮蔽换类型修复代码要求下面代码想先存字符串长度再存字符串本身但顺序反了导致类型冲突。请用 shadowing 修复。fnmain(){letshello.len();// usizeletshello;// str想改成这个顺序println!({},s);}参考答案fnmain(){letshello;// strletss.len();// usize类型变了合法println!({},s);// 5}解读shadowing 允许变量换类型。如果这里用 mut第一次 let s “hello” 后类型就锁定为 str再赋 usize 会编译失败。 练习 5mut vs shadowing判断对错以下两段代码哪段能编译为什么Afnmain(){letmutx5;xhello;}Bfnmain(){letx5;letxhello;}参考答案A 编译失败B 编译通过。解读A 用 mutx 的类型在第一次赋值时就锁定为整数后面赋字符串类型不匹配报错 mismatched types。B 用 shadowing第二次 let x 创建了一个全新的变量类型可以自由变。 练习 6综合计算圆面积要求· 定义常量 PI: f64 3.14159· 定义变量 radius初始为 2.0可修改· 先把 radius 改为 3.0· 用 shadowing 创建 area PI * radius * radius· 打印面积参考答案constPI:f643.14159;fnmain(){letmutradius2.0;radius3.0;letareaPI*radius*radius;println!(面积 {:.2},area);// 面积 28.27}解读radius 需要改所以用 mut。area 只算一次不再改用普通 let。{:.2} 是格式化占位符保留两位小数。 思考题 1为什么 Rust 默认不可变参考答案三个层面的理由安全性大多数并发 bug 和逻辑 bug 来自意外修改。默认不可变让编译器在编译期拦截这些问题。可读性看到 let x 5 就知道 x 不会变读代码时不用追踪后续所有赋值。看到 let mut x 就知道要小心修改意图是显式的。性能不可变数据更容易优化编译器可以放心做内联、缓存。同时不可变引用可以安全地跨线程共享。解读这是 Rust “零成本抽象”和“安全优先”哲学的体现。不是限制你而是让你在需要可变时才付可变的代价。 思考题 2const 和 static 到底该用哪个参考答案优先用 const。const 是编译期常量使用时被内联到代码里没有固定内存地址适合大多数“配置值”场景比如 const MAX: u32 100;。static 有固定内存地址全局唯一。适合需要取地址、需要跨线程共享、或者值很大不想被多处复制的情况。constNAME:strRust;// 推荐staticGREETING:strHello;// 需要地址时才用解读新手 99% 的场景用 const 就够了。static mut 是 unsafe 的涉及全局可变状态除非必要不要碰后面讲并发时会再提到。 思考题 3shadowing 会带来性能开销吗参考答案不会。shadowing 只是创建了一个新的栈上变量或直接复用寄存器编译器会做优化。旧的变量如果之后不再使用会被直接释放或优化掉。实际上shadowing 常常让代码更清晰比如把字符串转成数字letinput42;letinput:i32input.parse().unwrap();比 let input_str …; let input_num … 更简洁也避免了一堆 _str、_num 后缀。解读shadowing 是 Rust 里非常常用的惯用法尤其在类型转换、数据加工链中。放心用。三、知识点总结第2课默认不可变let x 5 后不能改需要改用 let mut x 5。常量const NAME: Type value;必须标类型、全大写、编译期可计算。静态变量static有固定地址全局唯一多数场景用 const 替代。变量遮蔽同名 let 创建新变量可换类型是惯用法。mut vs shadowingmut 同一变量类型不变shadowing 新变量类型可变。作用域花括号 {} 创建新作用域内层遮蔽不影响外层。格式化{:.2} 保留两位小数{} 默认填充。四、下一课预告第3课数据类型· 标量类型整数、浮点、布尔、字符· 复合类型元组、数组· 类型推断与显式标注· 整数溢出与 checked_* 系列方法 本课心法不可变是默认可变是选择。每写一个 mut都是在向编译器声明“我知道这里会变我为此负责”。