文章目录

image-20260921074625266

Rust 常用函数/方法/语法速查手册

用途:写代码时随手查,不用每次都去翻官方文档。按"我要干什么"分类,不是按语言特性分类,方便直接定位。

目录

  1. 字符串处理(String / &str)
  2. 数字与类型转换
  3. Vec 常用方法
  4. HashMap 常用方法
  5. Option 常用方法
  6. Result 常用方法
  7. 迭代器常用方法
  8. 输入输出(io)
  9. 常用语法糖 / 技巧
  10. 格式化打印速查({} 里能写什么)
  11. 常见类型速查表
  12. 网络编程常用(std::net)
  13. 常见报错对照表

1. 字符串处理(String / &str)

先搞清楚 String&str 的关系String 是"拥有所有权、可增长"的字符串(存在堆上);&str 是"借用的字符串切片"(只读,不拥有数据)。字符串字面量 "abc" 的类型就是 &str。函数参数优先写 &str(更通用,String 能自动转成 &str 传进去)。

方法签名(简化)作用示例
.len()&self -> usize字节长度(不是字符数!中文占3字节)"abc".len()3
.trim()&self -> &str去掉首尾空白(含换行符)" 8080\n".trim()"8080"
.is_empty()&self -> bool是否为空字符串"".is_empty()true
.contains(pat)&self, &str/char -> bool是否包含子串/字符"a.b".contains('.')true
.starts_with(pat)&self, &str -> bool是否以...开头"https://x".starts_with("https")true
.ends_with(pat)&self, &str -> bool是否以...结尾"file.txt".ends_with(".txt")true
.split(pat)&self, &str/char -> Iterator按分隔符切分,返回迭代器"1-100".split('-')["1","100"]
.splitn(n, pat)同上+限制份数最多切成n份"a:b:c".splitn(2,':')["a","b:c"]
.replace(from, to)&self, &str, &str -> String替换所有匹配"a-b".replace("-","_")"a_b"
.to_string()&self -> String&str转String"abc".to_string()
.to_owned()&self -> String效果同to_string()"abc".to_owned()
String::from(s)&str -> String效果同to_string(),更常见写法String::from("abc")
.as_str()&self -> &strString转&str(借用)s.as_str()
.push_str(s)&mut self, &str在末尾追加字符串s.push_str("world")
.push(c)&mut self, char在末尾追加单个字符s.push('!')
.insert_str(i, s)&mut self, usize, &str在指定位置插入字符串s.insert_str(0, "https://")
.to_uppercase()&self -> String转大写"abc".to_uppercase()"ABC"
.to_lowercase()&self -> String转小写"ABC".to_lowercase()"abc"
.parse::<T>()&self -> Result<T, E>解析成数字等类型"8080".parse::<u16>()
.chars()&self -> Iterator<char>按字符遍历(处理中文安全)for c in s.chars() {}
.bytes()&self -> Iterator<u8>按字节遍历for b in s.bytes() {}
.trim_start_matches(pat)&self, &str -> &str去掉开头的匹配内容url.trim_start_matches("https://")
format!(...)宏,同println!语法拼字符串(不打印,返回String)format!("{}:{}", ip, port)

记忆技巧:凡是"看一眼、判断"的方法(len/is_empty/contains/starts_with),签名都是 &self;凡是"改内容"的(push_str/insert_str),签名都是 &mut self;凡是"生成新字符串"的(replace/to_uppercase),都返回一个全新的 String,不改原字符串。


2. 数字与类型转换

操作写法说明
字符串转数字s.parse::<u32>()返回 Result<u32, ParseIntError>,可能失败
数字转字符串n.to_string()几乎所有数字类型都有这个方法
数字转数字(安全,可能失败)u16::try_from(300_i32)返回 Result,超范围会是 Err
数字转数字(不检查,会截断)n as u16⚠️ 超范围会静默截断出错误值,谨慎使用
判断奇偶n % 2 == 0没有专门的is_even方法
取绝对值n.abs()仅有符号类型(i32等)有
最大/最小值a.max(b) / a.min(b)两数比较
类型的最大/最小值u16::MAX / u16::MIN常量,u16::MAX是65535
四舍五入(浮点数)f.round()还有 .floor()向下、.ceil()向上

记忆技巧as 转换是"暴力转换",超出目标类型范围会出乱码般的错误结果(不会报错,是"静默"出错,最容易埋雷);try_from 是"安全转换",超范围直接给你 Err,写校验逻辑(比如端口号范围检查)优先用 try_from 或手动比较范围。


3. Vec 常用方法

方法签名(简化)作用示例
Vec::new()-> Vec<T>创建空Veclet v: Vec<u32> = Vec::new();
vec![...]创建并初始化Vecvec![1, 2, 3]
.push(x)&mut self, T尾部添加元素v.push(80)
.pop()&mut self -> Option<T>移除并返回最后一个元素v.pop()Some(80)None
.len()&self -> usize元素个数v.len()
.is_empty()&self -> bool是否为空v.is_empty()
.get(i)&self, usize -> Option<&T>安全获取(越界返回None,不panic)v.get(0)
v[i]索引访问直接取值(越界会panic!v[0]
.contains(&x)&self, &T -> bool是否包含某元素v.contains(&80)
.sort()&mut self原地排序(从小到大)v.sort()
.sort_by_key(f)&mut self, closure按指定规则排序`v.sort_by_key(\x\x.port)`
.reverse()&mut self原地反转顺序v.reverse()
.iter()&self -> Iterator<&T>借用迭代(不拿走所有权)for x in v.iter() {}
.into_iter()self -> Iterator<T>拿走所有权的迭代for x in v.into_iter() {}
.first() / .last()&self -> Option<&T>第一个/最后一个元素v.first()
.clear()&mut self清空所有元素v.clear()
.remove(i)&mut self, usize -> T移除指定下标元素(会移动后面所有元素,O(n)v.remove(0)
.retain(f)&mut self, closure保留满足条件的元素,原地过滤`v.retain(\x\*x > 100)`
.extend(iter)&mut self, IntoIterator把另一个集合的元素全部加进来v.extend(vec![4,5])
.concat()用于 Vec<Vec<T>>把多个Vec拼成一个[[1,2],[3,4]].concat()[1,2,3,4]

记忆技巧v[i] 越界直接崩程序(panic),v.get(i) 越界给你 None——处理不确定来源的下标(比如用户输入的索引)一定用 .get(),不要直接用 []


4. HashMap 常用方法

use std::collections::HashMap;
方法签名(简化)作用示例
HashMap::new()-> HashMap<K,V>创建空maplet mut m: HashMap<u16,bool> = HashMap::new();
.insert(k, v)&mut self, K, V -> Option<V>插入(如果key已存在,返回旧值)m.insert(80, true)
.get(&k)&self, &K -> Option<&V>查找,找不到返回Nonem.get(&80)
.get_mut(&k)&mut self, &K -> Option<&mut V>查找并拿到可变引用(可以直接改)if let Some(v) = m.get_mut(&80) { *v = false; }
.contains_key(&k)&self, &K -> bool是否存在某keym.contains_key(&80)
.remove(&k)&mut self, &K -> Option<V>删除并返回值m.remove(&80)
.entry(k).or_insert(v)链式调用key不存在就插入默认值,存在就返回现有值的可变引用*m.entry(80).or_insert(0) += 1;
.keys()&self -> Iterator<&K>遍历所有keyfor k in m.keys() {}
.values()&self -> Iterator<&V>遍历所有valuefor v in m.values() {}
.iter()&self -> Iterator<(&K,&V)>遍历所有键值对for (k,v) in m.iter() {}
.len()&self -> usize键值对数量m.len()

记忆技巧entry().or_insert() 是统计计数的标准套路("没有就建、有就累加"),几乎每个用HashMap做统计的场景都会用到,务必记熟。遍历顺序不保证,需要有序输出要额外 .sort() 或换 BTreeMap


5. Option 常用方法

方法作用示例
.is_some()是否有值opt.is_some()
.is_none()是否为空opt.is_none()
.unwrap()取值,None时panic(慎用)opt.unwrap()
.unwrap_or(default)取值,None时用默认值opt.unwrap_or(0)
.unwrap_or_else(f)取值,None时调用闭包生成默认值`opt.unwrap_or_else(\\compute())`
.unwrap_or_default()取值,None时用类型的默认值(0/空串等)opt.unwrap_or_default()
.map(f)有值就转换,None还是None`opt.map(\x\x * 2)`
.and_then(f)有值就调用f(f本身返回Option),常用于链式操作`opt.and_then(\x\if x>0 {Some(x)} else {None})`
.ok_or(err)转成Result,None变成Err(err)opt.ok_or("没找到")
if let Some(x) = opt { ... }只关心有值的情况常用写法,比match简洁

记忆技巧.map() 是"有值就加工一下,还是Option";.and_then() 是"有值就调用一个'本身也返回Option'的函数,避免出现Option<Option>这种嵌套"。


6. Result 常用方法

方法作用示例
.is_ok()是否成功res.is_ok()
.is_err()是否失败res.is_err()
.unwrap()取值,Err时panic(慎用,只适合原型阶段)res.unwrap()
.unwrap_or(default)取值,Err时用默认值res.unwrap_or(0)
.ok()转成Option,Err变成None(丢弃错误信息)res.ok()
.map(f)成功值加工一下`res.map(\x\x * 2)`
.map_err(f)转换错误类型/错误信息`res.map_err(\e\format!("失败:{}",e))`
?失败直接把Err向上抛,成功取出值继续let x = risky_fn()?;
.expect(msg)类似unwrap,panic时带自定义提示信息res.expect("连接必须成功")

记忆技巧:正式代码里,尽量不用 unwrap(),改用 match?、或者 .unwrap_or(默认值);只有在写原型/测试代码,图快的时候才用 unwrap()expect(msg)unwrap() 稍好一点,至少panic时能看到你写的提示信息,方便定位问题。


7. 迭代器常用方法

先转成迭代器:.iter()(借用)/ .into_iter()(拿走所有权)/ .iter_mut()(可变借用)

方法作用示例
.filter(f)保留满足条件的元素`v.iter().filter(\x\**x > 100)`
.map(f)把每个元素转换成别的`v.iter().map(\x\x * 2)`
.collect()把迭代器收集成具体集合(Vec/HashMap等),常需要类型标注let v: Vec<u16> = iter.collect();
.count()统计满足条件的数量v.iter().filter(...).count()
.sum()求和let total: u32 = v.iter().sum();
.max() / .min()最大/最小值,返回Optionv.iter().max()
.find(f)找第一个满足条件的元素,返回Option`v.iter().find(\x\**x == 80)`
.any(f)是否存在满足条件的元素,返回bool`v.iter().any(\x\*x > 1000)`
.all(f)是否所有元素都满足条件`v.iter().all(\x\*x > 0)`
.enumerate()附带下标一起遍历for (i, x) in v.iter().enumerate() {}
.zip(other)两个迭代器一一配对a.iter().zip(b.iter())
.take(n)只取前n个v.iter().take(5)
.skip(n)跳过前n个v.iter().skip(5)
.rev()反转顺序v.iter().rev()
.chain(other)把两个迭代器接在一起a.iter().chain(b.iter())
.for_each(f)对每个元素执行操作(不返回新集合)`v.iter().for_each(\x\println!("{}", x))`
.partition(f)一次遍历,按条件分成两个集合`let (a, b): (Vec<_>,Vec<_>) = v.iter().partition(\x\**x>100);`

记忆技巧:迭代器方法都是"链式调用",可以一直 . 下去(v.iter().filter(...).map(...).collect()),中间过程都是"懒执行"(不会立刻算),只有调用了 .collect()/.count()/.sum() 这类"消费型"方法才会真正触发计算——这个特性叫"惰性求值",性能上比每一步都生成中间Vec要好。


8. 输入输出(io)

use std::io;
操作写法说明
读一行输入io::stdin().read_line(&mut s)s必须是&mut String,返回Result<usize,Error>(usize是字节数)
打印(带换行)println!("{}", x)
打印(不换行)print!("{}", x)有时需要手动use std::io::Write; io::stdout().flush().unwrap();才会立刻显示
打印到标准错误eprintln!("{}", x)命令行工具打印错误信息的惯例,不是标准输出
调试打印(打印结构体等)println!("{:?}", x)需要类型实现Debug(大部分标准类型自动支持,自定义struct需要#[derive(Debug)]
美化调试打印println!("{:#?}", x)多行缩进格式,适合复杂结构体/嵌套数据

9. 常用语法糖 / 技巧

// if let:只关心Option/Result的一种情况时,比match简洁
if let Some(x) = opt {
    println!("{}", x);
}

// while let:循环处理,直到不满足模式为止(比如不断从Vec里pop)
while let Some(x) = stack.pop() {
    println!("{}", x);
}

// ? 运算符:错误/None向上传播(第6章重点)
let x = risky()?;

// 元组解构
let (a, b) = (1, 2);
let (min, max) = (ports.iter().min(), ports.iter().max());

// 数组/Vec的模式匹配(match)
match arr.as_slice() {
    [] => println!("空"),
    [x] => println!("只有一个: {}", x),
    [first, .., last] => println!("首:{} 尾:{}", first, last),
}

// 用 _ 忽略不需要的值
let (_, port) = ("192.168.1.1", 8080);
for _ in 0..3 { /* 不需要循环变量时 */ }

// 链式Option/Result判断多个条件(match guard)
match port {
    p if p < 1024 => println!("知名端口"),
    p if p < 49152 => println!("注册端口"),
    _ => println!("动态端口"),
}

// 一行式条件表达式(if是表达式,有返回值)
let status = if port == 80 { "http" } else { "other" };

// 结构体更新语法:基于已有实例创建新实例,只改部分字段
let t2 = Target { port: 443, ..t1 };

// #[derive(...)] 自动实现常用trait,不用手写
#[derive(Debug, Clone, PartialEq)]
struct Target { ip: String, port: u16 }
// Debug: 支持 {:?} 打印
// Clone: 支持 .clone()
// PartialEq: 支持 == 比较

10. 格式化打印速查({} 里能写什么)

println!("{}", x);        // Display格式(人类可读)
println!("{:?}", x);      // Debug格式(调试用,需要类型支持)
println!("{:#?}", x);     // 美化的Debug格式,多行缩进
println!("{:5}", x);      // 最小宽度5,右对齐(数字默认)补空格
println!("{:<5}", x);     // 左对齐,宽度5
println!("{:>5}", x);     // 右对齐,宽度5
println!("{:^5}", x);     // 居中,宽度5
println!("{:05}", x);     // 宽度5,不足补0(常用于格式化IP/端口对齐)
println!("{:.2}", f);     // 浮点数保留2位小数
println!("{:x}", n);      // 十六进制小写(网络包分析常用)
println!("{:X}", n);      // 十六进制大写
println!("{:08x}", n);    // 十六进制,宽度8,补0(常见于格式化MAC地址/十六进制dump)
println!("{:b}", n);      // 二进制
println!("{:o}", n);      // 八进制
println!("{name}", name=x);  // 具名参数
println!("{0} {1} {0}", a, b); // 按位置索引,可重复引用

11. 常见类型速查表

类型说明常见用途
u80~255字节数据,网络包解析常用
u160~65535端口号(刚好匹配范围)
u320~约42亿一般计数、IPv4地址的数字形式
u64更大范围时间戳、大文件大小
i32有符号,约-21亿~21亿一般整数运算,默认整数类型
usize平台相关(64位系统通常是u64)集合长度、索引,len()都返回这个
f64双精度浮点默认浮点类型
booltrue/false
char单个Unicode字符(4字节)
&str字符串切片(借用)函数参数首选
String拥有所有权的字符串需要修改/长期持有时用
Vec<T>动态数组
[T; N]固定长度数组(编译期确定N)[u8; 4]常表示IPv4地址的4个字节
&[T]数组/Vec的切片(借用)函数参数,比&Vec<T>更通用
Option<T>可能有值可能没有
Result<T,E>可能成功可能失败
(A,B,...)元组,固定个数、可以不同类型简单地打包少量数据,不想专门定义struct时用

12. 网络编程常用(std::net)

use std::net::{TcpStream, TcpListener, SocketAddr, IpAddr, Ipv4Addr};
use std::time::Duration;

// 建立TCP连接(阻塞,一直等到成功或失败)
let stream = TcpStream::connect("127.0.0.1:8080");

// 建立TCP连接,带超时(网络工具里更常用,避免一直卡住)
let addr: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let stream = TcpStream::connect_timeout(&addr, Duration::from_millis(500));

// 监听端口(写服务端/简单的listener时用)
let listener = TcpListener::bind("0.0.0.0:8080").unwrap();
for stream in listener.incoming() {
    // 处理每个连接
}

// 手动构造IP地址
let ip = Ipv4Addr::new(192, 168, 1, 1);

// 判断字符串是不是合法IP
let is_valid: bool = "192.168.1.1".parse::<IpAddr>().is_ok();

reqwest(HTTP客户端,需要额外加依赖)常用写法

// 同步(简单场景)
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking"] }
let resp = reqwest::blocking::get("https://example.com")?;
println!("{}", resp.status());
println!("{}", resp.text()?);

// 异步(推荐,性能更好)
// Cargo.toml: reqwest = "0.12", tokio = { version = "1", features = ["full"] }
let resp = reqwest::get("https://example.com").await?;
let body = resp.text().await?;

13. 常见报错对照表

报错关键字原因怎么修
value borrowed after move变量被移动后又用.clone(),或改用引用&T
cannot borrow ... as mutable同时存在可变和不可变引用缩短某个引用的存活范围,让借用不重叠
cannot move out of ... which is behind a shared reference试图从&T里拿走所有权.clone()拿一份,或改成只用引用
mismatched types类型对不上检查是不是String/&str没转,或数字类型不一致
the trait bound ... is not satisfied用了某个方法但类型没实现对应trait常见于自定义struct忘了加#[derive(Debug)]
use of moved value用了已经被移动走的变量同"value borrowed after move"
missing lifetime specifier函数返回引用但编译器无法推断存活多久加生命周期标注'a,或改成返回String(拿所有权,不用操心生命周期)
unused variable (warning)变量声明了没用不影响运行,可以在变量名前加_消除警告,如let _x = 5;
E0502 / E0382 等错误码Rust错误码可以直接把错误码丢进搜索引擎,官方文档对每个错误码都有详细解释和示例

使用建议:这份手册按"我要干什么"分类,不用背,遇到问题先想"我要做的事属于哪一类"(字符串处理?集合操作?错误处理?),来这里对应章节查表,比每次都搜索引擎慢慢翻要快。写多了自然就记住了。
版权属于:厂长
本文链接:https://bishepro.com/archives/rustex.html
本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!