Rust基本语法
一、Rust基础概述
1.1 语法设计目标
- 安全、并发、性能并重,静态强类型与零成本抽象。
- 表达式为核心,尽量在编译期发现问题。
- 生态与工具链:
rustup管理工具链,cargo构建与依赖管理,rust-analyzer提升 IDE 体验。
1.2 程序基本结构
fn main() {println!("Hello, Rust");
}
二、变量、所有权与借用
2.1 变量、常量与遮蔽
讲解:变量默认不可变,使用 mut 声明可变变量;遮蔽允许用同名新绑定覆盖旧值但保持不可变语义;const 为编译期常量,需显式类型。
示例:完整可执行的变量、遮蔽与常量演示
fn main() {let x = 1;let x = x + 1;let mut y = 0;y += 1;const MAX: u32 = 100_000;println!("x={}", x);println!("y={}", y);println!("MAX={}", MAX);
}
2.2 所有权、移动、复制与克隆
讲解:String 等堆分配类型在赋值时会发生所有权移动;clone 执行深拷贝保留两个独立所有权;诸如整数等实现 Copy 的标量类型按值复制,无需移动。
示例:完整可执行的所有权与克隆演示
fn main() {let s = String::from("hi");let t = s;println!("moved: {}", t);let u = t.clone();println!("cloned: t={}, u={}", t, u);let a = 1;let b = a;println!("copy: a={}, b={}", a, b);
}
2.3 借用与可变借用
讲解:不可变借用允许只读访问;可变借用在同一时刻只能存在一个以保证数据一致性;借用不转移所有权。
示例:完整可执行的借用演示
fn len(s: &String) -> usize { s.len() }
fn push_exclaim(s: &mut String) { s.push_str("!") }fn main() {let mut s = String::from("a");let l = len(&s);println!("len={}", l);push_exclaim(&mut s);println!("{}", s);
}
2.4 切片与字符串
讲解:切片是对集合的只读视图,不拥有数据;字符串切片按字节索引,需保证落在 UTF-8 字符边界。
示例:完整可执行的切片演示
fn main() {let a = [1, 2, 3, 4];let slice = &a[1..3];println!("{:?}", slice);let s = String::from("hello");let r: &str = &s[0..2];println!("{}", r);
}
三、类型与数据结构
3.1 基本类型、元组、数组与切片
讲解:Rust 的标量与复合类型具备显式类型与固定大小;数组在栈上分配、长度固定;切片为只读视图。
示例:完整可执行的类型演示
fn main() {let i: i32 = -1;let f: f64 = 3.14;let b: bool = true;let c: char = '中';let tup: (i32, &str) = (7, "a");let (n, s) = tup;let arr: [i32; 3] = [1, 2, 3];let slice: &[i32] = &arr[..];println!("i={}, f={}, b={}, c={}", i, f, b, c);println!("tup=({}, {})", n, s);println!("arr={:?}", arr);println!("slice={:?}", slice);
}
3.2 String 与 &str
讲解:String 可变且拥有堆数据;&str 为只读借用的字符串视图;两者互补使用。
示例:完整可执行的字符串演示
fn main() {let mut s = String::from("hi");s.push_str("!");let r: &str = &s;println!("String={}", s);println!("&str={}", r);
}
3.3 结构体与实现
讲解:struct 定义数据结构,impl 块中可添加关联函数与方法;方法的第一个参数为接收者 &self 或 &mut self。
示例:完整可执行的结构体方法演示
struct Point { x: i32, y: i32 }
impl Point {fn new(x: i32, y: i32) -> Self { Self { x, y } }fn norm(&self) -> f64 { ((self.x.pow(2) + self.y.pow(2)) as f64).sqrt() }
}fn main() {let p = Point::new(3, 4);println!("{}", p.norm());
}
3.4 枚举与模式匹配
讲解:enum 可表达代数数据类型;match 覆盖所有分支并支持解构与条件守卫。
示例:完整可执行的枚举匹配演示
enum Shape { Circle(f64), Rect { w: i32, h: i32 } }
fn area(s: Shape) -> f64 {match s {Shape::Circle(r) => 3.14159 * r * r,Shape::Rect { w, h } => (w * h) as f64,}
}fn main() {let c = Shape::Circle(2.0);let r = Shape::Rect { w: 3, h: 4 };println!("{}", area(c));println!("{}", area(r));
}
3.5 Option 与 Result
讲解:Option 表示可空值,促使显式处理缺失情况;Result 表示可能出错的操作,结合 match 或 ? 传播错误。
示例:完整可执行的 Option 与 Result 演示
fn find(v: &[i32], x: i32) -> Option<usize> {for (i, n) in v.iter().enumerate() {if *n == x { return Some(i); }}None
}fn main() {let v = vec![1, 2, 3];match find(&v, 2) {Some(i) => println!("found at {}", i),None => println!("not found"),}let ok = "42".parse::<i32>();let err = "x".parse::<i32>();match ok { Ok(n) => println!("ok {}", n), Err(e) => println!("error {}", e) }match err { Ok(n) => println!("ok {}", n), Err(e) => println!("error {}", e) }
}
四、函数、控制流与闭包
4.1 函数与返回值
讲解:函数返回值以尾表达式形式出现,无需 return;类型推断在参数位置较保守,需显式类型。
示例:完整可执行的函数演示
fn add(a: i32, b: i32) -> i32 { a + b }fn main() {let r = add(2, 3);println!("{}", r);
}
4.2 控制流
讲解:if 是表达式可赋值;for 基于迭代器;loop 可构建无限循环并通过 break 退出。
示例:完整可执行的控制流演示
fn main() {let x = if true { 1 } else { 2 };println!("{}", x);for i in 0..3 { println!("{}", i); }let mut n = 0;while n < 3 { n += 1; println!("{}", n); }let mut k = 0;loop {k += 1;if k == 2 { break; }}println!("{}", k);
}
4.3 match 与 if let / while let
讲解:match 要覆盖所有可能分支;if let、while let 简化对特定模式的处理。
示例:完整可执行的模式演示
fn main() {let v = Some(1);match v {Some(n) if n > 0 => println!("positive"),Some(_) => println!("non-positive"),None => println!("none"),}if let Some(n) = v { println!("{}", n); }let mut it = Some(0);while let Some(n) = it {if n == 2 { it = None; } else { it = Some(n + 1); }println!("{}", n);}
}
4.4 闭包与捕获
讲解:闭包可自动推断参数与返回类型,并按需以不可变/可变/按值捕获环境变量。
示例:完整可执行的闭包演示
fn main() {let mut n = 0;let mut f = |x: i32| { n += x; n };println!("{}", f(2));println!("{}", f(3));let v = vec![1, 2, 3];let s: i32 = v.iter().map(|x| x * 2).sum();println!("{}", s);
}
五、模块、泛型、生命周期与并发
5.1 模块与包结构
讲解:mod 定义子模块,pub 决定对外可见性;use 简化路径;二进制 crate 入口为 main.rs。示例以内联模块展示。
示例:完整可执行的模块演示
mod utils {pub fn greet(name: &str) -> String { format!("Hello, {}", name) }
}
fn main() {let s = utils::greet("Rust");println!("{}", s);
}
5.2 Trait 与泛型
讲解:Trait 描述行为接口;泛型结合 trait bounds 实现约束;零成本抽象避免运行时开销。
示例:完整可执行的 trait 与泛型演示
trait Area { fn area(&self) -> f64; }
struct Circle { r: f64 }
struct Rect { w: f64, h: f64 }
impl Area for Circle { fn area(&self) -> f64 { 3.14159 * self.r * self.r } }
impl Area for Rect { fn area(&self) -> f64 { self.w * self.h } }
fn sum<T: std::ops::Add<Output=T> + Copy>(a: T, b: T) -> T { a + b }
fn print_area<T: Area>(s: &T) { println!("{}", s.area()); }fn main() {let c = Circle { r: 2.0 };let r = Rect { w: 3.0, h: 4.0 };print_area(&c);print_area(&r);println!("{}", sum(1, 2));println!("{}", sum(1.5, 2.5));
}
5.3 生命周期
讲解:生命周期参数声明引用至少存活到返回值使用完;编译器借助省略规则自动推断多数场景。
示例:完整可执行的生命周期演示
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y }
}fn main() {let a = String::from("abcd");let b = String::from("xyz");let r = longest(&a, &b);println!("{}", r);
}
5.4 集合与迭代器
讲解:集合位于标准库;迭代器链支持惰性计算与组合操作;HashMap 提供键值存储与借用访问。
示例:完整可执行的集合与迭代器演示
use std::collections::HashMap;fn main() {let v = vec![1, 2, 3, 4];let even_sum: i32 = v.iter().filter(|n| *n % 2 == 0).sum();println!("{}", even_sum);let mut m = HashMap::new();m.insert("a", 1);m.insert("b", 2);if let Some(x) = m.get("a") { println!("{}", x); }for (k, v) in &m { println!("{} {}", k, v); }
}
5.5 智能指针与并发
讲解:Rc<T> 在单线程中实现共享所有权;并发下用 Arc<T> 提供原子引用计数,搭配 Mutex<T> 进行互斥访问;线程通过 spawn 创建并在 join 等待完成。
示例:完整可执行的智能指针与并发演示
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::thread;fn main() {let a = Rc::new(String::from("x"));let b = Rc::clone(&a);println!("{} {}", a, b);let c = Arc::new(Mutex::new(0));let mut handles = vec![];for _ in 0..4 {let c2 = Arc::clone(&c);handles.push(thread::spawn(move || {let mut n = c2.lock().unwrap();*n += 1;}));}for h in handles { h.join().unwrap(); }println!("{}", *c.lock().unwrap());
}
5.6 代码质量与测试
讲解:cargo fmt 统一代码风格;cargo clippy 静态诊断建议;测试框架内置,使用 #[test] 标记。
示例:在同一文件中包含测试与可执行入口
#[cfg(test)]
mod tests {fn add(a: i32, b: i32) -> i32 { a + b }#[test]fn it_works() { assert_eq!(add(2, 2), 4); }
}fn main() {println!("run `cargo test` to execute tests");
}
常用命令:
cargo fmt
cargo clippy
cargo test
