作为一门系统级编程语言,Rust以其独特的所有权机制和内存安全保障著称。但在掌握这些高级特性前,我们需要先夯实基础。本篇将深入探讨Rust的核心编程概念,这些是后续学习复杂特性的基石。
Rust的变量默认不可变(immutable),这是其安全哲学的重要体现。想象你正在编写一个财务系统,某个代表汇率的变量被多处引用,如果它被意外修改,后果将不堪设想。Rust通过默认不可变的变量设计,从语言层面避免了这类问题。
提示:虽然可变性需要显式声明看似增加了代码量,但在大型项目中,这个特性可以避免许多难以追踪的bug。
Rust使用let关键字声明变量,默认情况下所有绑定都是不可变的:
rust复制let x = 5;
x = 6; // 编译错误!不能对不可变变量二次赋值
要使变量可变,需添加mut关键字:
rust复制let mut x = 5;
x = 6; // 合法操作
这种设计带来了几个优势:
常量使用const声明,必须显式标注类型:
rust复制const MAX_POINTS: u32 = 100_000;
与不可变变量的关键区别:
Rust允许使用同名变量覆盖前一个变量:
rust复制let x = 5;
let x = x + 1; // 合法遮蔽
遮蔽与可变性的关键区别:
rust复制let spaces = " ";
let spaces = spaces.len(); // 合法:改变类型
let mut spaces = " ";
spaces = spaces.len(); // 非法:类型不匹配
Rust的整数类型明确区分大小和有无符号:
| 长度 | 有符号 | 无符号 |
|---|---|---|
| 8-bit | i8 | u8 |
| 16-bit | i16 | u16 |
| 32-bit | i32 | u32 |
| 64-bit | i64 | u64 |
| arch | isize | usize |
选择建议:
i32:在大多数现代CPU上性能最优usize:与内存布局匹配u16对应端口号调试模式下,Rust会检查整数溢出并panic。发布模式(--release)下,会执行二进制补码环绕:
rust复制let mut x: u8 = 255;
x += 1; // 调试模式panic,发布模式变为0
明确处理溢出的方法:
rust复制x.wrapping_add(1); // 明确要求环绕
x.checked_add(1); // 返回Option
x.overflowing_add(1); // 返回(结果, 溢出标志)
Rust有f32和f64两种浮点,默认f64(现代CPU上性能与f32相当但精度更高)。
特殊浮点值:
INFINITY/NEG_INFINITYNAN(非数字)注意:直接比较
NAN会得到false,应使用is_nan()方法
Rust的char是4字节Unicode标量值,与字符串中的UTF-8编码不同:
rust复制let c = '😻'; // 合法char
let s = "😻"; // &str类型,UTF-8编码
元组是固定长度的异构集合:
rust复制let tup: (i32, f64, u8) = (500, 6.4, 1);
访问方式:
rust复制let (x, y, z) = tup;
rust复制tup.0 // 访问第一个元素
数组是固定长度的同构集合,存储在栈上:
rust复制let a: [i32; 5] = [1, 2, 3, 4, 5];
特殊初始化语法:
rust复制let a = [3; 5]; // 等同于[3,3,3,3,3]
数组越界是运行时错误(panic),Rust会在编译期尽可能检查简单的越界情况。
Rust函数签名必须明确参数和返回类型:
rust复制fn add(x: i32, y: i32) -> i32 {
x + y // 注意没有分号,这是一个表达式
}
关键区别:
rust复制let y = {
let x = 1;
x + 1 // 表达式,返回x+1的值
}; // y=2
函数体最后的表达式自动作为返回值,也可用return提前返回:
rust复制fn max(a: i32, b: i32) -> i32 {
if a > b {
a // 表达式返回
} else {
return b; // return语句
}
}
if条件必须是bool类型,不支持隐式转换:
rust复制if x != 0 { // 明确的条件判断
// ...
}
if也是表达式,可以用于赋值:
rust复制let number = if condition { 5 } else { 6 };
最基本的无限循环,可带返回值:
rust复制let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
条件循环,没有返回值:
rust复制while number != 0 {
println!("{}", number);
number -= 1;
}
最安全的集合遍历方式:
rust复制for element in a.iter() {
println!("value: {}", element);
}
范围表达式:
rust复制for number in (1..4).rev() {
println!("{}", number); // 打印3,2,1
}
虽然Rust有强大的类型推断,但在以下情况建议显式标注类型:
rust复制let v: Vec<_> = (0..10).collect(); // 帮助推断collect的目标类型
mutrust复制// 更高效的写法
let sum: i32 = (1..100).sum();
Rust的这些基础概念虽然简单,但体现了其"零成本抽象"的设计哲学。理解这些特性背后的设计意图,能帮助我们在后续学习中更好地掌握所有权、生命周期等高级特性。