rustup 工具链管理 cargo 项目构建(new/build/run/test/check/clean/doc) rustc 编译器 rustdoc 文档生成
[package] name="hello" version="0.1.0" edition="2021" [dependencies] fn main() { println!("Hello, world!"); }
fn gcd(mut n: u64, mut m: u64) -> u64 { assert!(n != 0 && m != 0); // 假→panic while m != 0 { // 条件无需括号 if m < n { let t = m; m = n; n = t; } // let自动推断 m = m % n; } n // 最后无分号=返回值 }
#[test] fn test_gcd() { assert_eq!(gcd(14, 15), 1); assert_eq!(gcd(2*3*5*11*17, 3*7*11*13*19), 3*11); }
use std::env; use std::str::FromStr; fn main() { let mut nums = Vec::new(); for arg in env::args().skip(1) { // 跳过程序名 nums.push(u64::from_str(&arg).expect("err")); // 解析→失败panic } if nums.len() == 0 { eprintln!("usage: gcd n1 n2 .."); // →stderr std::process::exit(1); } let mut d = nums[0]; for m in &nums[1..] { d = gcd(d, *m); } // &引用 *解引用 println!("GCD={}", d); }
let x = 5; let mut x = 5; x = 6; let x = 5; let x = x + 1; { let x = x * 2; } let y = { let z = x * x; z / 2 }; (-4_i32).abs() -4_i32.abs()
u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64
0x_0fff_ffff_i32 0o1670isize 0b11110000u8 b'A' = 65u8 b'\x41' = 65u8 b'\n' = 10u8
1000_i16 as i8 → -24_i8 -1_i16 as i32 → -1_i32 65535_u16 as i32 → 65535_i32
100_u8.checked_add(200) → None 500_u16.wrapping_mul(500) → 53392 255_u8.overflowing_add(2) → (1, true) 32760_i16.saturating_add(10) → 32767
let s1 = String::from("hello"); let s2 = s1; // s1所有权→s2 s1无效→E0382
v.remove(i) v.swap_remove(i) v.pop() std::mem::replace(&mut v[i], new) std::mem::take(&mut v[i]) vec![Some(v), None]
use std::rc::Rc; let s: Rc<String> = Rc::new(String::from("hi")); let t = s.clone(); // ref count=2 let u = Rc::clone(&s); // ref count=3 count→0堆释放
let r = &value; // &T copy type 共享引用 let rm = &mut value; // &mut T non-copy 可变引用 *rm = 456; // 解引用: 通过&mut修改指向的值
// * 显式解引用: 从引用访问到它所指向的值 let value: i32 = 123; let refer = &value; let v2: i32 = *refer; // *refer → 123 assert_eq!(value, *refer); // . 操作符自动deref: 编译器自动插入* 对Box/Rc也适用 let b = Box::new(String::from("hi")); b.len(); // 自动 *b → String 再 .len() 不需写(*b).len() let rc = Rc::new(42); rc.count_ones(); // 自动 *rc → i32 再 .count_ones() // . 操作符会自动ref: 调用&self方法时自动取引用 let v = vec![1,2,3]; v.len(); // 自动 (&v).len() Vec::len(&self) // Deref Coercion (隐式转换): 编译器在特定位置自动插入deref // &String → &str &Vec<T> → &[T] &Box<T> → &T &mut T → &T fn show(s: &str) { .. } let name = String::from("hi"); show(&name); // &String 自动转 &str (Deref trait: String→str)
fn smallest(v: &[i32]) -> &i32 { // 返回引用 elision自动补全 let mut s = &v[0]; for r in &v[1..] { if *r < *s { s = r; } } s }
static mut STASH: &i32 = &0; fn stash(r: &'static i32) { unsafe { STASH = r; } }
let x = if cond { 1 } else { 0 }; match code { 0 => println!("OK"), _ => println!("Unknown") } if let Some(v) = opt { .. } else { .. } while cond {..} while let Some(v) = iter.next() {..} for &e in &v {..} 0..5 0..=5 loop { break val; } 'outer: loop { break 'outer v; } return expr; let name: type = expr;
enum Result<T, E> { Ok(T), Err(E) } rst.is_ok() rst.is_err() rst.unwrap() rst.expect(msg) rst.unwrap_or(fb) rst.unwrap_or_else(f) rst.ok() rst.err() rst.as_ref()→Result<&T, &E> rst.as_mut()→Result<&mut T, &mut E>
let v = foo(...)?; fn main() -> Result<(), Box<dyn std::error::Error>> { Ok(()) }
enum E { A, B(i32, String), C{x: f64, y: f64} }
match self { InThePast(TimeUnit::Hour, 1) => format!("an hour ago"), // 最具体 InThePast(unit, 1) => format!("a {} ago", unit.singular()), InThePast(unit, count) => format!("{} {} ago", count, unit.plural()), JustNow => format!("just now"), InTheFuture(unit, count) => format!("{} {} from now", count, unit.plural()), }
struct P { x: f64, y: f64 } struct C(u8, u8, u8); struct U;
impl P { fn new(x: f64, y: f64) -> Self { P{x, y} } fn len(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } const ZERO: P = P{x: 0.0, y: 0.0}; }
struct Queue<T> { older: Vec<T>, younger: Vec<T> } impl<T> Queue<T> { fn new() -> Self { Queue { older: vec![], younger: vec![] } } fn push(&mut self, v: T) { self.younger.push(v); } fn pop(&mut self) -> Option<T> { if self.older.is_empty() { self.younger.reverse(); self.older.append(&mut self.younger); } self.older.pop() } }
// 四种等价调用 — 运算符形式不需要use Add 方法形式需要 10_i32 + 32_i32 // 运算符形式 10_i32.add(32_i32) // 方法调用(需 use std::ops::Add) std::ops::Add::add(10_i32, 32_i32) // Qualified Method Call <i32 as std::ops::Add>::add(10, 32) // Fully Qualified Method Call
算术: +→Add(add) -→Sub(sub) *→Mul(mul) /→Div(div) %→Rem(rem) 位: &→BitAnd |→BitOr ^→BitXor !→Not <<→Shl >>→Shr 一元: -→Neg !→Not 复合: +=→AddAssign -=→SubAssign ... (与二元不同trait! 各需单独impl) 比较: == != → PartialEq(eq,ne默认) / Eq(标记自反性) < <= > >= → PartialOrd(partial_cmp→Option<Ordering>) / Ord 索引: a[i] → Index(index→&Output) a[i]=v → IndexMut(index_mut→&mut Output)
pub trait Add<Rhs = Self> { // Rhs=右侧操作数类型 默认=Self type Output; // 关联类型: 加法结果的类型 fn add(self, rhs: Rhs) -> Self::Output; }
// Step1: 特化 Complex<f64> impl Add for Complex<f64> { type Output = Self; fn add(self, r: Self) -> Self::Output {..} } // Step2: 泛化 T+T=T → Complex<T>+Complex<T>=Complex<T> impl<T> Add for Complex<T> where T: Add<Output = T> { type Output = Self; fn add(self, rhs: Self) -> Self::Output { Complex { re: self.re + rhs.re, im: self.im + rhs.im } } } // Step3: 更宽松 L+R=O → Complex<L>+Complex<R>=Complex<O> impl<L, R> Add<Complex<R>> for Complex<L> where L: Add<R> { type Output = Complex<L::Output>; .. } // 引用版本: impl Add for &Complex<T> 或用 &'a T: Add<&'b T> 放松lifetime约束
// Complex<i32>✅Eq Complex<f32>❌Eq (因f32不满足自反性) // PartialOrd: f32/f64是标准库仅有的不实现Ord的类型(NAN→None不可比) // derive: #[derive(PartialEq,Eq,PartialOrd,Ord)]需所有字段已实现对应trait
impl<P> Index<usize> for Image<P> { type Output = [P]; fn index(&self, row: usize) -> &[P] { let start = row * self.width; &self.pixels[start..start + self.width] } }
fn gcd(mut n: u64, mut m: u64) -> u64 { assert!(n != 0 && m != 0); while m != 0 { if m < n { let t = m; m = n; n = t; } m = m % n; } n } #[test] fn test() { assert_eq!(gcd(14, 15), 1); }
// Copy (i32) — 复制值 let n1: i32 = 36; let n2 = n1; // n1仍然可用 // Non-Copy (String) — 所有权转移 let s1 = String::from("dog"); let s2 = s1; // s1无效! E0382 // 从Vec移出元素 let mut v = vec![String::from("a"), String::from("b")]; let e = std::mem::replace(&mut v[0], String::from("x")); // v→["x","b"] e="a" let e = std::mem::take(&mut v[0]); // v→["","b"] e="x" (String Default="")
use std::rc::Rc; let s: Rc<String> = Rc::new(String::from("Hello World!")); let t = s.clone(); let u = Rc::clone(&s);
fn smallest(v: &[i32]) -> &i32 { let mut s = &v[0]; for r in &v[1..] { if *r < *s { s = r; } } s } static mut STASH: &i32 = &0; fn stash(r: &'static i32) { unsafe { STASH = r; } }
// if let — match语法糖 只关心一个pattern if let Some(v) = option_value { println!("{}", v); } else { println!("none"); } // while let — 遇None自动停止 while let Some(s) = a[i] { rst.push(s); i += 1; } // match — 穷尽性检查 + 模式解构 let name = match optional_name { Some(v) => v, None => String::from("Stranger") }; // loop + labeled break 返回值 let sqrt = 'outer: loop { n += 1; for i in 1.. { let sq = i * i; if sq == n { break 'outer i; } if sq > n { break; } } };
// ? 操作符 — Err时提前return 自动From::from转换错误 fn read_file() -> Result<String, std::io::Error> { let mut s = String::new(); File::open("hello.txt")?.read_to_string(&mut s)?; Ok(s) } // 自定义错误类型 + impl From → ?自动转换 enum MyError { Io(std::io::Error), Parse(std::num::ParseIntError) } impl From<std::io::Error> for MyError { fn from(e: std::io::Error) -> Self { MyError::Io(e) } } impl From<std::num::ParseIntError> for MyError { fn from(e: std::num::ParseIntError) -> Self { MyError::Parse(e) } } fn process() -> Result<i32, MyError> { let s = std::fs::read_to_string("data.txt")?; // io::Error→MyError::Io let n: i32 = s.trim().parse()?; // ParseIntError→MyError::Parse Ok(n) }
struct Queue<T> { older: Vec<T>, younger: Vec<T> } impl<T> Queue<T> { fn new() -> Self { Queue { older: vec![], younger: vec![] } } fn push(&mut self, v: T) { self.younger.push(v); } fn pop(&mut self) -> Option<T> { if self.older.is_empty() { self.younger.reverse(); self.older.append(&mut self.younger); } self.older.pop() } }
use std::cell::Cell; let c = Cell::new(42); c.set(c.get() + 1); use std::cell::RefCell; let rc = RefCell::new(String::from("hi")); *rc.borrow_mut() = String::from("hey");
pub trait Write { fn write(&mut self, buf: &[u8]) -> Result<usize>; // 必须实现 fn flush(&mut self) -> Result<()>; // 必须实现 fn write_all(&mut self, buf: &[u8]) -> Result<()> { // 默认实现 let mut n = 0; while n < buf.len() { n += self.write(&buf[n..])?; } Ok(()) } fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> {..} // 默认实现 }use std::io::Write; struct Sink; impl Write for Sink { fn write(&mut self, buf: &[u8]) -> Result<usize> { Ok(buf.len()) } fn flush(&mut self) -> Result<()> { Ok(()) } } let mut sink = Sink; sink.write_all("hello".as_bytes())?;
use std::ops::Add; struct Complex<T> { re: T, im: T } impl<T> Add for Complex<T> where T: Add<Output = T> { type Output = Self; fn add(self, rhs: Self) -> Self::Output { Complex { re: self.re + rhs.re, im: self.im + rhs.im } } }
Ownership 每值唯一owner 离scope→drop(逆序) move后原owner不可用(E0382) Borrow &T:共享只读多共存,copy &mut T:独占读写最多一 两者互斥 Lifetime 引用不可比所指值活更久 elision自动补全 'static=全程 Copy 赋值复制值(非move) 数字/char/bool/全Copy数组元组 Clone .clone()深拷贝 非Copy也可实现 Drop 离scope自动调 创建逆序释放 可drop(v)提前 Move 赋值/传参/返回/元组/for迭代non-copy 条件if→变量失效 Partial Move 单独移走struct某字段 其余仍可用 Sized 编译期已知大小 [T]和dyn Trait是!Sized(DST) ?Sized放宽 Send 可跨线程转移所有权 Rc/RefCell不是Send Arc/Mutex是 Sync 可跨线程共享引用 T:Sync iff &T:Send Cell/RefCell不是Sync
assert_eq!( 1000_i16 as i8, -24_i8); // 截断溢出 assert_eq!( -1_i16 as i32, -1_i32); // 符号扩展 assert_eq!(10_u8.checked_add(20), Some(30)); assert_eq!(500_u16.wrapping_mul(500), 53392); println!("{}", f64::NAN == f64::NAN); // false!
struct Extrema<'elt> { greatest: &'elt i32, least: &'elt i32 } enum Json { Null, Number(f64), String(String), Array(Vec<Json>), Object(Box<HashMap<String, Json>>) } // Box打破递归大小
fn draw_dyn(shapes: &[Box<dyn Draw>]) {..} // 动态 vtable 可存多种类型 fn draw_gen<T: Draw>(shapes: &[T]) {..} // 静态 单态化 零开销 fn<T, U>(x: T, y: U) -> T where T: Clone + Debug, U: PartialEq {..}
Vec<T> — 堆变长数组(ptr+len+cap) 越界索引→panic v.push(x) 末尾加元素 v.pop() -> Option<T> 末尾弹出 v.insert(i, x) i位插入 后续元素后移 O(n) v.remove(i) -> T i位移除 后续元素前移 O(n) v.swap_remove(i) -> T 末位替换i位 低成本 无序 v.len() / v.capacity() 当前长度/容量 len≤cap v.sort() / v.reverse() 排序/反转 T:Ord HashMap<K,V> — 哈希表 K:Eq+Hash map.insert(k, v) 插入 返回旧值Option<V> map.get(&k) -> Option<&V> 查询 返回引用 map.remove(&k) -> Option<V> 删除+返回 map.entry(k).or_insert(v) 占位:有则返&mut V 无则插入v String — Vec<u8> UTF-8变长 .len()→字节数! .chars().count()→字符数 s.push(c) / s.push_str(ss) 追加字符/字符串 s.pop() -> Option<char> 弹出末尾字符 s.insert(i, c) i位插入 越界→panic &str — 切片引用 不可变 s.parse::<T>() -> Result<T,E> 字符串解析为数字等 s.split(p) / s.trim() 分割迭代器 / 去首尾空格 Option<T> — Some(T)|None 替代null opt.unwrap() -> T None→panic! opt.expect("msg") -> T None→panic+msg opt.unwrap_or(def) -> T None→默认值def opt.map(|x|..) -> Option<U> Some→变换 None→None opt.and_then(|x|..) -> Opt<U> Some→f(x) None→None(不嵌套) opt.as_ref() -> Option<&T> &Option→Option<&T> 避免消费 opt.take() -> Option<T> 取走值 原位变None opt? None→return None Result<T,E> — Ok(T)|Err(E) ?=Err→return Err.into() r.unwrap()/expect("msg") Err→panic! 消费所有权 r.map(|x|..) -> Result<U,E> Ok→变换 Err不变 r.map_err(|e|..) -> R<T,F> Err→变换 Ok不变 r.and_then(|x|..) -> R<U,E> Ok→f(x) Err不变(不嵌套) r.as_ref() -> Result<&T,&E> 避免消费 &Result→Result<&T,&E> 迭代器 — 惰性(不触发求值) 消费者触发求值 .iter()/.iter_mut()/.into_iter() 不可变/可变/所有权迭代 .map(|x|..) .filter(|x|bool) 变换/过滤(惰性) .collect::<Vec<_>>() .fold(init,|a,x|..) 收集/折叠(消费) .enumerate() .zip(other) 加索引/拉链 .find(|x|bool) .any(|x|bool) .all(|x|bool) 查找/任一/全满足(消费) (0..n) (0..=n) 左闭右开/闭区间
cargo new <name> [--lib] cargo build [--release] cargo run [-- args] cargo check cargo test [pat] [-- --nocap] cargo doc [--open] cargo clean cargo update cargo fmt / clippy cargo publish [--dry-run] RUST_BACKTRACE=1 cargo run println!("{}",x) eprintln!("err") format!("x={x}") assert!(cond) assert_eq!(a,b) panic!("msg") todo!() unreachable!() vec![a,b,c] vec![v;100] dbg!(&x) include_str!("f") concat!(a,b) matches!(expr,pat) #[derive(Debug,Clone,Copy,PartialEq,Eq,Hash,Default,PartialOrd,Ord)] #[test] #[should_panic] #[ignore] #[allow/warn/deny(x)] #[cfg(target_os="linux")] #[cfg(debug_assertions)] #[repr(C/align(N)/packed)] #[inline] #[cold] #![crate_type="lib"] Cargo.toml: [package] name version(MAJOR.MINOR.PATCH) edition("2021") [dependencies] name="ver" (^1.2.3兼容1.x ~1.2.3兼容1.2.x >=1.2,<2.0) [dev-dependencies] [build-dependencies] [profile.dev] opt-level=0 [profile.release] opt-level=3 [workspace] members=["p1","p2"]
E0382 use of moved value E0507 cannot move out of index E0597 does not live long enough E0502 cannot borrow immut + mut E0506 cannot assign (borrowed) E0384 assign twice to immutable E0308 mismatched types E0004 non-exhaustive patterns E0277 trait bound not satisfied E0204 trait Copy may not be impl'd E0604 only u8 can cast as char E0606 casting bool as f32 invalid E0054 cannot cast as bool E0596 cannot borrow (Rc) as mut E0608 cannot index into a value E0594 cannot assign to *refer (& ref) E0381 use of possibly-uninit var
fn main() { let mut v = vec![String::from("a"), String::from("b")]; let r = &v[0]; v.push(String::from("c")); println!("{}", r); }