Rust 编程指南·酷色篇 #02 | 认识变量
变量定义,Rust 的基石
变量是编程的基础,就像画家的调色盘一样。但在不同的编程语言中,变量有着截然不同的"性格"。
JavaScript 的变量:像变色龙,随时可以改变类型和值,自由但危险。
Java/Dart 的变量:像严格的管家,类型固定但值可变,但变量默认可以被修改。
Rust 的变量:像严历的守护者,默认不可变但允许显式改变,保证值的安全。
在 Rust 中,变量不仅仅是存储数据的容器,更是内存安全的守护者。让我们通过彩色输出来直观地学习 Rust 的变量定义!
1 基本变量定义
变量有什么用呢?让我们先看看没有变量时的情况,注意观察重复出现的 \x1b[0m 重置码:
fn main() {
// 频繁重复的重置码 - 看起来很冗余
println!("\x1b[31m红色文本\x1b[0m");
println!(" \x1b[32m绿色文本\x1b[0m");
println!(" \x1b[34m蓝色文本\x1b[0m");
println!(" \x1b[33m黄色文本\x1b[0m");
}
可以看到 \x1b[0m 重复了4次!如果要修改重置方式,需要改4个地方。现在让我们用变量来优化:注: println 中可以使用 {} 来放置一个变量名称:
fn main() {
// 提取变量后 - 清晰且易维护
let red = "\x1b[31m";
let green = "\x1b[32m";
let blue = "\x1b[34m";
let yellow = "\x1b[33m";
let reset = "\x1b[0m"; // 变量的价值体现!
println!("{red}红色文本{reset}");
println!(" {green}绿色文本{reset}");
println!(" {blue}蓝色文本{reset}");
println!(" {yellow}黄色文本{reset}");
}
变量的价值体现:通过提取 reset 变量,我们实现了:
- 统一管理:一处定义,处处使用
- 易于维护:修改重置方式只需改一个地方
- 代码清晰:语义更明确,可读性更强
运行这段代码,你会看到彩色的文本输出。这些颜色变量一旦定义,就不能再改变了。

为什么默认不可变?
这体现了 Rust 的设计哲学:安全优于便利。就像现实生活中,我们更愿意把贵重物品放在保险箱里,而不是随意摆放。
- 内存安全:防止意外修改
- 并发安全:多线程环境下更安全
- 性能优化:编译器可以做更多优化
哲学思考:不可变性让我们重新思考"改变"的含义。真正的改变不是破坏原有的,而是创造新的。
2 可变变量
当你需要改变变量的值时,使用 mut 关键字。
fn main() {
// 使用变量后 - 统一管理重置码
let red = "\x1b[31m";
let green = "\x1b[32m";
let blue = "\x1b[34m";
let reset = "\x1b[0m"; // 一处定义,处处使用
let mut current_color = red;
println!("{current_color}初始是红色{reset}" );
current_color = green;
println!(" {current_color}现在是绿色{reset}" );
current_color = blue;
println!(" {current_color}又变成蓝色{reset}");
}
这就像有一个可以调节的调色盘,你可以随时切换颜色。
设计对比:
- 其他语言:变量默认可变,“自由但混乱”
- Rust 语言:变量默认不可变,“约束中的自由”
这种设计让我们在需要改变时更加谨慎和明确,就像在说:“我知道我在做什么,我要改变这个变量。”
3 类型声明
Rust 有强大的类型推断,但有时我们需要明确指定类型。其中 u8 是无符号8位整数,取值范围 0-255;正好对应 RGB 颜色值的范围
fn main() {
let r: u8 = 255;
let g: u8 = 128;
let b: u8 = 64;
let reset = "\x1b[0m"; // 提取重置码变量
println!("\x1b[38;2;{r};{g};{b}mRGB红色{reset}");
println!("\x1b[38;2;0;{g};{b}m绿蓝混合{reset}");
println!("\x1b[38;2;{r};0;{b}m红蓝混合{reset}");
}
类型声明的场景:
- 编译器无法推断时
- 需要特定类型时(如
u8而不是i32) - 提高代码可读性时
4 常量定义
常量在编译时就确定值,整个程序运行期间都不会改变。让我们看看常量如何解决重复代码问题:
fn main() {
// 硬编码方式 - 重置码到处都是
print!("\x1b[31m错误\x1b[0m");
print!(" \x1b[33m警告\x1b[0m");
print!(" \x1b[32m成功\x1b[0m");
print!(" \x1b[34m信息\x1b[0m");
print!(" \x1b[35m调试\x1b[0m");
println!();
}
这里 \x1b[0m 出现了5次!用常量优化后:
fn main() {
// 常量定义 - 统一管理,体现变量价值
const RED: &str = "\x1b[31m";
const YELLOW: &str = "\x1b[33m";
const GREEN: &str = "\x1b[32m";
const BLUE: &str = "\x1b[34m";
const MAGENTA: &str = "\x1b[35m";
const RESET: &str = "\x1b[0m"; // 关键变量!
println!("{RED}错误{RESET}");
println!("{YELLOW}警告{RESET}");
println!("{GREEN}成功{RESET}");
println!("{BLUE}信息{RESET}");
println!("{MAGENTA}调试{RESET}");
}
常量 vs 变量:
| 特性 | 常量 const |
不可变变量 let |
|---|---|---|
| 声明时机 | 编译时 | 运行时 |
| 作用域 | 全局或模块 | 块级作用域 |
| 命名规范 | 大写+下划线 | 小写+下划线 |
| 类型声明 | 必须 | 可选 |
5 变量遮蔽
Rust 允许用相同名字声明新变量,这叫做"遮蔽"。
fn main() {
let reset = "\x1b[0m"; // 统一的重置码
let color = "\x1b[31m";
println!("{color}第一次是红色{reset}");
let color = "\x1b[32m"; // 遮蔽前一个 color
println!("{color}第二次是绿色{reset}");
let color = "\x1b[34m"; // 再次遮蔽
println!("{color}第三次是蓝色{reset}");
// 甚至可以改变类型
let color = color.len();
println!("长度是{color}");
}
遮蔽的优势:
- 可以改变变量类型
- 避免起新名字(如
color_str→color_len) - 保持变量不可变性
哲学思考:遮蔽体现了"重生"的概念。旧的变量"死去",新的变量"诞生",它们只是恰好有相同的名字。这不是改变,而是替换。
就像河流中的水,看似是同一条河,实际上每一刻的水都是不同的。变量遮蔽让我们能够在保持不可变性的同时,实现"变化"的效果。
6 解构赋值
可以一次性从复合数据中提取多个值。先说说元组:元组 就像一个小盒子,里面可以放不同类型的东西。比如 (255, 128, 64) 就是一个装了3个数字的小盒子,用圆括号包起来,逗号分隔。元组的好处是可以把相关的数据打包在一起,比如 RGB 颜色的三个分量。
fn main() {
let reset = "\x1b[0m";
// 元组解构 - 分解 RGB 值
let rgb_color = (255, 128, 64); // 创建一个元组
let (r, g, b) = rgb_color; // 把元组拆开,分别赋给 r、g、b
println!("\x1b[38;2;{r};{g};{b}m解构得到 R={r}, G={g}, B={b}{reset}");
// 数组解构 - 颜色名称
let colors = ["红", "绿", "蓝"];
let [first, second, third] = colors;
println!("\x1b[31m{first} \x1b[32m{second} \x1b[34m{third}{reset}");
// 部分解构
let rgba = (255, 128, 64, 0.8);
let (red, green, ..) = rgba; // 忽略后面的值
println!("\x1b[38;2;{red};{green};0m只用前两个分量: R={red}, G={green}{reset}");
}
7 变量作用域
变量的生命周期由作用域决定:
fn main() {
let reset = "\x1b[0m";
let outer_color = "\x1b[31m"; // 外部作用域
println!("{outer_color}外部红色{reset}");
{ // 内部作用域开始
let inner_color = "\x1b[32m"; // 内部作用域
println!("{inner_color}内部绿色{reset}");
println!("{outer_color}内部访问外部{reset}"); // 可以访问外部
} // inner_color 在这里被销毁
println!("{outer_color}回到外部{reset}");
// println!("{inner_color}"); // 编译错误!
}
总结
通过彩色输出,我们学习了 Rust 变量定义的核心概念:
核心要点:
- 默认不可变:
let变量默认不可变,需要mut才能修改 - 类型安全:强类型系统,支持类型推断和显式注解
- 常量机制:
const在编译时确定,性能更好 - 遮蔽特性:允许重新定义同名变量,甚至改变类型
- 解构赋值:优雅地从复合数据中提取值
- 作用域管理:变量生命周期由作用域决定
这些特性让 Rust 在保证内存安全的同时,提供了极大的编程灵活性。变量定义虽然基础,却是 Rust 安全性和性能的重要基石。
深层思考:
Rust 的变量设计体现了一种平衡的智慧:
- 保守与激进:默认不可变(保守),但允许显式可变(激进)
- 约束与自由:类型约束(严格),但有类型推断(灵活)
- 安全与性能:内存安全(安全),零成本抽象(性能)
这种设计哲学告诉我们:真正的自由不是无约束的放纵,而是在合理约束下的明智选择。就像交通规则不是限制我们的自由,而是让我们能够安全、高效地到达目的地。
编程人生感悟:
- 变量的不可变性教会我们:稳定是珍贵的
- 显式的可变性教会我们:改变需要深思熟虑
- 变量遮蔽教会我们:有时候重新开始比修修补补更好
- 作用域教会我们:万物皆有生命周期,珍惜当下
下一步:让我们探索 Rust 的函数的封装,看看如何用进一步简化代码!
更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。让我们一起成长,变得更强。我们下次再见~
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)