1 IO流
1.1 分类
01.IO流分为3种
第1种:按照【流的方向】划分:【输入流】、【输出流】
第2种:按照【操作单元】划分:【字节流】、【字符流】
第3种:按照【缓冲方式】划分:【缓冲流】、【非缓冲流】
02.按照【操作单元】划分
a.字节流
a.Read trait
用于从数据源读取字节数据,适用于所有类型的IO操作。
b.Write trait
用于向目标写入字节数据,适用于所有类型的IO操作。
b.字符流
a.BufRead trait
提供按行读取和缓冲读取功能,适用于文本处理。
b.字符串处理
Rust中字符串默认UTF-8编码,通过String和str类型处理文本数据。
03.字节流与字符流
a.数据类型
字节流:处理原始字节数据,适用于二进制文件和网络传输。
字符流:处理UTF-8编码的文本数据,适用于文本文件。
b.trait基础
字节流:基于Read和Write trait。
字符流:基于BufRead trait和String类型。
c.编码处理
字节流:不考虑字符编码问题,直接处理字节。
字符流:自动处理UTF-8编码,适合处理文本数据。
d.使用场景
字节流:适用于处理非文本数据,如图像、音频、视频。
字符流:适用于处理文本数据,如配置文件、日志文件。
04.缓冲流与非缓冲流
a.功能不同
缓冲流:使用内存缓冲区减少系统调用次数,提高IO效率。
非缓冲流:直接进行IO操作,每次读写都会触发系统调用。
b.使用场景
缓冲流:适用于频繁读写操作的场景,如文件复制、网络传输。
非缓冲流:适用于需要立即刷新数据的场景,如实时日志。
c.API不同
缓冲流:BufReader、BufWriter提供按行读取、批量写入等高级功能。
非缓冲流:File、TcpStream等直接提供基础的read和write方法。
1.2 标准输入输出:stdin、stdout、stderr
01.标准流概述
a.stdin标准输入
从控制台读取用户输入,对应文件描述符0。
b.stdout标准输出
向控制台输出正常信息,对应文件描述符1。
c.stderr标准错误
向控制台输出错误信息,对应文件描述符2。
02.stdin标准输入
a.基本用法
a.功能说明
使用std::io::stdin()获取标准输入句柄,通过read_line读取一行输入。
b.代码示例
---
use std::io;
fn main() {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("读取失败");
println!("输入内容: {}", input.trim());
}
---
b.锁定stdin
a.功能说明
使用lock()方法获取stdin的独占锁,避免多次获取句柄的开销。
b.代码示例
---
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
let mut handle = stdin.lock();
for line in handle.lines() {
println!("读取: {}", line.unwrap());
}
}
---
03.stdout标准输出
a.基本用法
a.功能说明
使用println!宏或std::io::stdout()输出内容到控制台。
b.代码示例
---
use std::io::{self, Write};
fn main() {
let mut stdout = io::stdout();
stdout.write_all(b"Hello, World!\n").unwrap();
stdout.flush().unwrap();
}
---
b.缓冲输出
a.功能说明
stdout默认是行缓冲的,遇到换行符或调用flush()时才会输出。
b.代码示例
---
use std::io::{self, Write};
fn main() {
print!("输入密码: ");
io::stdout().flush().unwrap();
let mut password = String::new();
io::stdin().read_line(&mut password).unwrap();
}
---
04.stderr标准错误
a.基本用法
a.功能说明
使用eprintln!宏或std::io::stderr()输出错误信息。
b.代码示例
---
use std::io::{self, Write};
fn main() {
eprintln!("错误: 文件不存在");
let mut stderr = io::stderr();
stderr.write_all(b"严重错误\n").unwrap();
}
---
b.重定向
a.功能说明
stdout和stderr可以分别重定向到不同的文件或设备。
b.代码示例
---
// 命令行重定向示例
// ./program > output.txt 2> error.txt
// stdout重定向到output.txt,stderr重定向到error.txt
fn main() {
println!("正常输出");
eprintln!("错误输出");
}
---
1.3 文件操作:File、OpenOptions
01.File基本操作
a.打开文件
a.功能说明
使用File::open()打开已存在的文件进行读取,使用File::create()创建新文件或覆盖已存在的文件。
b.代码示例
---
use std::fs::File;
use std::io::Read;
fn main() -> std::io::Result<()> {
// 打开文件读取
let mut file = File::open("input.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
println!("文件内容: {}", contents);
// 创建文件写入
let mut file = File::create("output.txt")?;
use std::io::Write;
file.write_all(b"Hello, Rust!")?;
Ok(())
}
---
b.文件元数据
a.功能说明
使用metadata()方法获取文件的元数据信息,包括大小、权限、修改时间等。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
let metadata = fs::metadata("file.txt")?;
println!("文件大小: {} 字节", metadata.len());
println!("是否为文件: {}", metadata.is_file());
println!("是否为目录: {}", metadata.is_dir());
println!("只读: {}", metadata.permissions().readonly());
if let Ok(modified) = metadata.modified() {
println!("修改时间: {:?}", modified);
}
Ok(())
}
---
02.OpenOptions高级选项
a.基本用法
a.功能说明
OpenOptions提供更灵活的文件打开方式,可以指定读、写、追加、创建等多种选项。
b.代码示例
---
use std::fs::OpenOptions;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open("data.txt")?;
file.write_all(b"追加内容\n")?;
Ok(())
}
---
b.追加模式
a.功能说明
使用append(true)选项在文件末尾追加内容,而不是覆盖原有内容。
b.代码示例
---
use std::fs::OpenOptions;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = OpenOptions::new()
.append(true)
.create(true)
.open("log.txt")?;
file.write_all(b"新日志条目\n")?;
Ok(())
}
---
03.文件操作函数
a.复制文件
a.功能说明
使用fs::copy()函数复制文件,返回复制的字节数。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
let bytes_copied = fs::copy("source.txt", "dest.txt")?;
println!("复制了 {} 字节", bytes_copied);
Ok(())
}
---
b.删除文件
a.功能说明
使用fs::remove_file()删除文件,如果文件不存在会返回错误。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
fs::remove_file("temp.txt")?;
println!("文件已删除");
Ok(())
}
---
c.重命名文件
a.功能说明
使用fs::rename()重命名或移动文件。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
fs::rename("old_name.txt", "new_name.txt")?;
println!("文件已重命名");
Ok(())
}
---
04.目录操作
a.创建目录
a.功能说明
使用fs::create_dir()创建单级目录,使用fs::create_dir_all()创建多级目录。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
// 创建单级目录
fs::create_dir("new_dir")?;
// 创建多级目录
fs::create_dir_all("path/to/nested/dir")?;
Ok(())
}
---
b.删除目录
a.功能说明
使用fs::remove_dir()删除空目录,使用fs::remove_dir_all()递归删除目录及其内容。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
// 删除空目录
fs::remove_dir("empty_dir")?;
// 递归删除目录
fs::remove_dir_all("dir_with_files")?;
Ok(())
}
---
1.4 读取器:Read trait
01.Read trait概述
a.定义
Read trait是Rust标准库中用于读取字节数据的核心trait,定义了从数据源读取数据的基本方法。
b.核心方法
read(&mut self, buf: &mut [u8]):从数据源读取数据到缓冲区,返回读取的字节数。
read_to_end(&mut self, buf: &mut Vec<u8>):读取所有数据到Vec。
read_to_string(&mut self, buf: &mut String):读取所有数据到String。
read_exact(&mut self, buf: &mut [u8]):精确读取指定长度的数据。
02.基本读取操作
a.read方法
a.功能说明
read方法从数据源读取数据到缓冲区,返回实际读取的字节数,返回0表示到达文件末尾。
b.代码示例
---
use std::fs::File;
use std::io::Read;
fn main() -> std::io::Result<()> {
let mut file = File::open("data.bin")?;
let mut buffer = [0u8; 1024];
loop {
let n = file.read(&mut buffer)?;
if n == 0 {
break;
}
println!("读取了 {} 字节", n);
// 处理buffer[..n]中的数据
}
Ok(())
}
---
b.read_to_end方法
a.功能说明
一次性读取所有数据到Vec<u8>,适用于文件大小未知的情况。
b.代码示例
---
use std::fs::File;
use std::io::Read;
fn main() -> std::io::Result<()> {
let mut file = File::open("image.png")?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
println!("读取了 {} 字节", contents.len());
Ok(())
}
---
03.文本读取
a.read_to_string方法
a.功能说明
读取所有数据并解析为UTF-8字符串,如果数据不是有效的UTF-8会返回错误。
b.代码示例
---
use std::fs::File;
use std::io::Read;
fn main() -> std::io::Result<()> {
let mut file = File::open("config.txt")?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
println!("文件内容:\n{}", contents);
Ok(())
}
---
b.便捷函数
a.功能说明
std::fs模块提供了read_to_string便捷函数,一行代码读取文件内容。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
let contents = fs::read_to_string("data.txt")?;
println!("内容: {}", contents);
// 读取二进制文件
let bytes = fs::read("image.png")?;
println!("文件大小: {} 字节", bytes.len());
Ok(())
}
---
04.精确读取
a.read_exact方法
a.功能说明
精确读取指定长度的数据,如果数据不足会返回UnexpectedEof错误。
b.代码示例
---
use std::fs::File;
use std::io::Read;
fn main() -> std::io::Result<()> {
let mut file = File::open("header.bin")?;
let mut header = [0u8; 16];
file.read_exact(&mut header)?;
println!("读取了16字节的头部数据");
Ok(())
}
---
b.链式读取
a.功能说明
Read trait提供了chain方法,可以将多个Reader连接起来顺序读取。
b.代码示例
---
use std::fs::File;
use std::io::{Read, Cursor};
fn main() -> std::io::Result<()> {
let file1 = File::open("part1.txt")?;
let file2 = File::open("part2.txt")?;
let mut combined = file1.chain(file2);
let mut contents = String::new();
combined.read_to_string(&mut contents)?;
println!("合并内容: {}", contents);
Ok(())
}
---
05.实现Read trait
a.自定义Reader
a.功能说明
为自定义类型实现Read trait,可以将其作为数据源使用。
b.代码示例
---
use std::io::{self, Read};
struct UppercaseReader<R> {
inner: R,
}
impl<R: Read> Read for UppercaseReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.inner.read(buf)?;
for byte in &mut buf[..n] {
if byte.is_ascii_lowercase() {
*byte = byte.to_ascii_uppercase();
}
}
Ok(n)
}
}
fn main() -> io::Result<()> {
let data = b"hello world";
let mut reader = UppercaseReader {
inner: &data[..],
};
let mut output = String::new();
reader.read_to_string(&mut output)?;
println!("{}", output); // 输出: HELLO WORLD
Ok(())
}
---
1.5 写入器:Write trait
01.Write trait概述
a.定义
Write trait是Rust标准库中用于写入字节数据的核心trait,定义了向目标写入数据的基本方法。
b.核心方法
write(&mut self, buf: &[u8]):向目标写入数据,返回写入的字节数。
write_all(&mut self, buf: &[u8]):写入所有数据,如果无法完全写入会返回错误。
flush(&mut self):刷新缓冲区,确保所有数据都被写入。
write_fmt(&mut self, fmt: Arguments):格式化写入,支持format!宏语法。
02.基本写入操作
a.write方法
a.功能说明
write方法向目标写入数据,返回实际写入的字节数,可能小于缓冲区大小。
b.代码示例
---
use std::fs::File;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = File::create("output.bin")?;
let data = b"Hello, Rust!";
let mut written = 0;
while written < data.len() {
let n = file.write(&data[written..])?;
written += n;
}
file.flush()?;
Ok(())
}
---
b.write_all方法
a.功能说明
write_all确保所有数据都被写入,如果无法完全写入会返回错误。
b.代码示例
---
use std::fs::File;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = File::create("data.txt")?;
file.write_all(b"第一行\n")?;
file.write_all(b"第二行\n")?;
file.write_all(b"第三行\n")?;
file.flush()?;
Ok(())
}
---
03.格式化写入
a.write_fmt方法
a.功能说明
使用write_fmt方法进行格式化写入,支持format!宏的所有格式化选项。
b.代码示例
---
use std::fs::File;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = File::create("log.txt")?;
let name = "Alice";
let age = 30;
writeln!(file, "姓名: {}", name)?;
writeln!(file, "年龄: {}", age)?;
writeln!(file, "时间: {:?}", std::time::SystemTime::now())?;
Ok(())
}
---
b.便捷宏
a.功能说明
write!和writeln!宏提供了便捷的格式化写入方式,类似于print!和println!。
b.代码示例
---
use std::fs::File;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = File::create("report.txt")?;
write!(file, "标题: ")?;
writeln!(file, "月度报告")?;
for i in 1..=5 {
writeln!(file, "项目{}: 完成", i)?;
}
Ok(())
}
---
04.缓冲区刷新
a.flush方法
a.功能说明
flush方法强制将缓冲区中的数据写入到底层设备,确保数据持久化。
b.代码示例
---
use std::fs::File;
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut file = File::create("important.txt")?;
file.write_all(b"重要数据")?;
file.flush()?; // 确保数据立即写入磁盘
println!("数据已安全写入");
Ok(())
}
---
b.自动刷新
a.功能说明
文件在Drop时会自动刷新,但显式调用flush可以更早地检测到写入错误。
b.代码示例
---
use std::fs::File;
use std::io::Write;
fn write_data() -> std::io::Result<()> {
let mut file = File::create("data.txt")?;
file.write_all(b"数据")?;
// 文件在这里Drop,自动刷新
Ok(())
}
fn main() {
if let Err(e) = write_data() {
eprintln!("写入失败: {}", e);
}
}
---
05.便捷函数
a.fs::write
a.功能说明
std::fs::write提供了一行代码写入文件的便捷方式,自动创建文件并写入数据。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
// 写入字节数据
fs::write("output.bin", b"binary data")?;
// 写入字符串
fs::write("output.txt", "文本内容")?;
Ok(())
}
---
b.实现Write trait
a.功能说明
为自定义类型实现Write trait,可以将其作为写入目标使用。
b.代码示例
---
use std::io::{self, Write};
struct CountingWriter {
count: usize,
}
impl Write for CountingWriter {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.count += buf.len();
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
fn main() -> io::Result<()> {
let mut writer = CountingWriter { count: 0 };
writeln!(writer, "Hello")?;
writeln!(writer, "World")?;
println!("写入了 {} 字节", writer.count);
Ok(())
}
---
1.6 缓冲IO:BufReader、BufWriter
01.缓冲IO概述
a.定义
缓冲IO通过在内存中维护缓冲区来减少系统调用次数,显著提高IO性能。
b.核心类型
BufReader:为Read类型提供缓冲功能,支持按行读取。
BufWriter:为Write类型提供缓冲功能,批量写入数据。
BufRead trait:定义了按行读取和缓冲读取的方法。
02.BufReader缓冲读取
a.基本用法
a.功能说明
BufReader包装一个Reader,提供内部缓冲区,减少read系统调用次数。
b.代码示例
---
use std::fs::File;
use std::io::{BufReader, Read};
fn main() -> std::io::Result<()> {
let file = File::open("large_file.txt")?;
let mut reader = BufReader::new(file);
let mut contents = String::new();
reader.read_to_string(&mut contents)?;
println!("读取了 {} 字节", contents.len());
Ok(())
}
---
b.按行读取
a.功能说明
BufReader实现了BufRead trait,提供lines()方法按行迭代读取文件。
b.代码示例
---
use std::fs::File;
use std::io::{BufReader, BufRead};
fn main() -> std::io::Result<()> {
let file = File::open("data.txt")?;
let reader = BufReader::new(file);
for (index, line) in reader.lines().enumerate() {
let line = line?;
println!("第{}行: {}", index + 1, line);
}
Ok(())
}
---
03.BufRead trait方法
a.read_line方法
a.功能说明
read_line读取一行数据(包括换行符)到String,返回读取的字节数。
b.代码示例
---
use std::fs::File;
use std::io::{BufReader, BufRead};
fn main() -> std::io::Result<()> {
let file = File::open("input.txt")?;
let mut reader = BufReader::new(file);
let mut line = String::new();
loop {
line.clear();
let n = reader.read_line(&mut line)?;
if n == 0 {
break;
}
print!("读取: {}", line);
}
Ok(())
}
---
b.read_until方法
a.功能说明
read_until读取数据直到遇到指定的分隔符字节。
b.代码示例
---
use std::fs::File;
use std::io::{BufReader, BufRead};
fn main() -> std::io::Result<()> {
let file = File::open("data.csv")?;
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();
loop {
buffer.clear();
let n = reader.read_until(b',', &mut buffer)?;
if n == 0 {
break;
}
println!("字段: {:?}", String::from_utf8_lossy(&buffer));
}
Ok(())
}
---
04.BufWriter缓冲写入
a.基本用法
a.功能说明
BufWriter包装一个Writer,提供内部缓冲区,批量写入数据以减少系统调用。
b.代码示例
---
use std::fs::File;
use std::io::{BufWriter, Write};
fn main() -> std::io::Result<()> {
let file = File::create("output.txt")?;
let mut writer = BufWriter::new(file);
for i in 1..=1000 {
writeln!(writer, "行 {}", i)?;
}
writer.flush()?;
Ok(())
}
---
b.自动刷新
a.功能说明
BufWriter在Drop时自动刷新缓冲区,但显式flush可以更早检测错误。
b.代码示例
---
use std::fs::File;
use std::io::{BufWriter, Write};
fn main() -> std::io::Result<()> {
let file = File::create("log.txt")?;
let mut writer = BufWriter::new(file);
writeln!(writer, "开始处理")?;
for i in 1..=100 {
writeln!(writer, "处理项目 {}", i)?;
if i % 10 == 0 {
writer.flush()?; // 每10行刷新一次
}
}
Ok(())
}
---
05.性能对比
a.无缓冲vs缓冲
a.功能说明
使用缓冲IO可以显著减少系统调用次数,提高IO性能,特别是在频繁读写小块数据时。
b.代码示例
---
use std::fs::File;
use std::io::{Write, BufWriter};
use std::time::Instant;
fn main() -> std::io::Result<()> {
// 无缓冲写入
let start = Instant::now();
let mut file = File::create("unbuffered.txt")?;
for i in 0..10000 {
writeln!(file, "行 {}", i)?;
}
println!("无缓冲耗时: {:?}", start.elapsed());
// 缓冲写入
let start = Instant::now();
let file = File::create("buffered.txt")?;
let mut writer = BufWriter::new(file);
for i in 0..10000 {
writeln!(writer, "行 {}", i)?;
}
writer.flush()?;
println!("缓冲耗时: {:?}", start.elapsed());
Ok(())
}
---
b.缓冲区大小
a.功能说明
可以通过with_capacity方法自定义缓冲区大小,默认为8KB。
b.代码示例
---
use std::fs::File;
use std::io::{BufReader, BufWriter};
fn main() -> std::io::Result<()> {
let file = File::open("input.txt")?;
let reader = BufReader::with_capacity(64 * 1024, file);
let file = File::create("output.txt")?;
let writer = BufWriter::with_capacity(64 * 1024, file);
println!("使用64KB缓冲区");
Ok(())
}
---
1.7 同步、异步、阻塞、非阻塞
00.汇总
同步IO、异步IO:程序等待IO操作完成的方式
阻塞IO、非阻塞IO:程序在等待IO操作完成时是否能继续执行其他操作
01.程序等待IO操作完成的方式
a.同步IO
a.定义
同步IO是指程序发起一个IO操作后,必须等待该操作完成并获取到结果后,才能继续执行后续代码。
b.特点
同步IO操作会阻塞程序的执行,直到IO操作完成。这意味着程序在等待IO操作期间不能执行其他任务。
c.示例
在Rust中,使用std::fs::File进行文件读写就是同步IO的例子。
b.异步IO
a.定义
异步IO是指程序发起一个IO操作后,不需要等待该操作完成,而是可以继续执行后续代码。IO操作完成后,程序会通过Future、回调或轮询等方式得到通知。
b.特点
异步IO不会阻塞程序的执行,允许程序在IO操作进行的同时执行其他任务,提高了程序的并发性和效率。
c.示例
在Rust中,使用tokio::fs::File进行文件读写就是异步IO的例子。
02.程序在等待IO操作完成时是否能继续执行其他操作
a.阻塞IO
a.定义
阻塞IO是指程序发起一个IO操作后,如果数据尚未准备好(如数据未到达、文件未找到等),程序会一直等待,直到数据准备好并完成IO操作。
b.特点
阻塞IO会导致程序的执行线程被挂起,直到IO操作完成。在这期间,线程不能执行其他任务。
c.示例
在Rust中,使用std::net::TcpStream进行网络通信时,read()方法就是阻塞IO的例子。
b.非阻塞IO
a.定义
非阻塞IO是指程序发起一个IO操作后,如果数据尚未准备好,IO操作会立即返回一个错误或特定值,而不是等待数据准备好。
b.特点
非阻塞IO允许程序在数据未准备好时继续执行其他任务,而不是等待。程序通常需要轮询或使用事件通知机制来检查IO操作的状态。
c.示例
在Rust中,使用mio库设置TcpStream为非阻塞模式,并使用Poll进行事件轮询,就是非阻塞IO的例子。
03.Rust中的实现
a.同步阻塞IO
a.功能说明
标准库中的IO操作默认是同步阻塞的,适合简单的IO场景。
b.代码示例
---
use std::fs::File;
use std::io::Read;
fn main() -> std::io::Result<()> {
let mut file = File::open("data.txt")?;
let mut contents = String::new();
// 阻塞直到读取完成
file.read_to_string(&mut contents)?;
println!("读取完成: {} 字节", contents.len());
Ok(())
}
---
b.异步非阻塞IO
a.功能说明
使用async/await和tokio运行时实现异步非阻塞IO,适合高并发场景。
b.代码示例
---
use tokio::fs::File;
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut file = File::open("data.txt").await?;
let mut contents = String::new();
// 异步读取,不阻塞线程
file.read_to_string(&mut contents).await?;
println!("读取完成: {} 字节", contents.len());
Ok(())
}
---
04.性能对比
a.同步IO适用场景
简单的文件操作、配置文件读取、小规模数据处理。
代码简单直观,易于理解和维护。
b.异步IO适用场景
高并发网络服务、大量IO操作、需要同时处理多个连接的场景。
可以用少量线程处理大量并发连接,提高资源利用率。
c.代码示例
a.功能说明
对比同步和异步IO在处理多个文件时的性能差异。
b.代码示例
---
// 同步IO:顺序处理
use std::fs;
fn sync_read_files() -> std::io::Result<()> {
for i in 1..=10 {
let contents = fs::read_to_string(format!("file{}.txt", i))?;
println!("文件{}: {} 字节", i, contents.len());
}
Ok(())
}
// 异步IO:并发处理
use tokio::fs;
async fn async_read_files() -> std::io::Result<()> {
let mut tasks = vec![];
for i in 1..=10 {
let task = tokio::spawn(async move {
let contents = fs::read_to_string(format!("file{}.txt", i)).await?;
println!("文件{}: {} 字节", i, contents.len());
Ok::<_, std::io::Error>(())
});
tasks.push(task);
}
for task in tasks {
task.await??;
}
Ok(())
}
---
05.选择建议
a.使用同步IO的情况
简单的命令行工具、脚本程序。
IO操作不频繁,性能要求不高。
代码简单性优先于性能。
b.使用异步IO的情况
Web服务器、API服务、聊天服务器等高并发场景。
需要同时处理大量IO操作。
性能和资源利用率是关键考虑因素。
2 序列化
2.1 定义
01.概念
序列化:将数据结构或对象转换为字节序列的过程,以便存储或传输。
反序列化:将字节序列转换回数据结构或对象的过程。
02.什么情况下需要序列化
1.网络传输:在网络上传输数据时需要将对象序列化为字节流。
2.持久化存储:将数据保存到文件或数据库时需要序列化。
3.进程间通信:不同进程之间传递数据需要序列化。
4.缓存:将对象序列化后存储到缓存系统中。
03.原因
数据结构在内存中的表示是复杂的,包含指针、引用等,无法直接存储或传输。
序列化提供了一种标准化的方式来表示数据,使得数据可以在不同系统、不同语言之间交换。
通过序列化,可以将内存中的数据转换为可存储、可传输的格式。
04.序列化的优点
跨平台:序列化后的数据可以在不同平台、不同语言之间交换。
持久化:将数据保存到文件或数据库,程序重启后可以恢复数据。
网络传输:将对象转换为字节流,方便在网络上传输。
版本兼容:通过合理的序列化格式设计,可以实现数据的向前和向后兼容。
05.Rust序列化特点
a.类型安全
Rust的类型系统确保序列化和反序列化过程的类型安全。
b.零成本抽象
serde库通过编译时代码生成,实现零运行时开销的序列化。
c.格式无关
serde提供统一的API,支持多种序列化格式(JSON、TOML、Bincode等)。
d.所有权系统
序列化过程遵循Rust的所有权规则,避免数据竞争和内存安全问题。
2.2 实现:serde
01.serde概述
a.定义
serde是Rust生态系统中最流行的序列化框架,提供高效、通用的序列化和反序列化功能。
b.核心特性
格式无关:支持JSON、TOML、YAML、Bincode等多种格式。
零成本抽象:通过derive宏在编译时生成代码,无运行时开销。
类型安全:利用Rust类型系统确保序列化的正确性。
可扩展:支持自定义序列化逻辑。
02.基本使用
a.添加依赖
a.功能说明
在Cargo.toml中添加serde和具体格式的依赖(如serde_json)。
b.代码示例
---
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
---
b.derive宏
a.功能说明
使用#[derive(Serialize, Deserialize)]为结构体自动实现序列化功能。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
email: String,
}
fn main() {
let user = User {
id: 1,
name: "Alice".to_string(),
email: "[email protected]".to_string(),
};
// 序列化为JSON
let json = serde_json::to_string(&user).unwrap();
println!("JSON: {}", json);
// 反序列化
let user2: User = serde_json::from_str(&json).unwrap();
println!("User: {:?}", user2);
}
---
03.序列化操作
a.to_string
a.功能说明
将对象序列化为字符串格式,适用于JSON、TOML等文本格式。
b.代码示例
---
use serde::{Serialize, Deserialize};
use serde_json;
#[derive(Serialize)]
struct Config {
host: String,
port: u16,
debug: bool,
}
fn main() {
let config = Config {
host: "localhost".to_string(),
port: 8080,
debug: true,
};
let json = serde_json::to_string(&config).unwrap();
println!("{}", json);
// 格式化输出
let json_pretty = serde_json::to_string_pretty(&config).unwrap();
println!("{}", json_pretty);
}
---
b.to_vec
a.功能说明
将对象序列化为字节数组,适用于二进制格式如Bincode。
b.代码示例
---
use serde::{Serialize, Deserialize};
use bincode;
#[derive(Serialize, Deserialize)]
struct Data {
values: Vec<i32>,
}
fn main() {
let data = Data {
values: vec![1, 2, 3, 4, 5],
};
let bytes = bincode::serialize(&data).unwrap();
println!("序列化后大小: {} 字节", bytes.len());
let data2: Data = bincode::deserialize(&bytes).unwrap();
println!("反序列化: {:?}", data2.values);
}
---
04.反序列化操作
a.from_str
a.功能说明
从字符串反序列化对象,适用于JSON、TOML等文本格式。
b.代码示例
---
use serde::{Serialize, Deserialize};
use serde_json;
#[derive(Deserialize, Debug)]
struct Response {
status: String,
code: i32,
message: String,
}
fn main() {
let json = r#"
{
"status": "success",
"code": 200,
"message": "操作成功"
}
"#;
let response: Response = serde_json::from_str(json).unwrap();
println!("{:?}", response);
}
---
b.from_slice
a.功能说明
从字节切片反序列化对象,适用于二进制格式。
b.代码示例
---
use serde::{Serialize, Deserialize};
use bincode;
#[derive(Serialize, Deserialize, Debug)]
struct Packet {
id: u32,
data: Vec<u8>,
}
fn main() {
let packet = Packet {
id: 42,
data: vec![1, 2, 3, 4],
};
let bytes = bincode::serialize(&packet).unwrap();
let packet2: Packet = bincode::deserialize(&bytes).unwrap();
println!("{:?}", packet2);
}
---
05.错误处理
a.Result类型
a.功能说明
序列化和反序列化操作返回Result类型,需要处理可能的错误。
b.代码示例
---
use serde::{Serialize, Deserialize};
use serde_json;
#[derive(Deserialize)]
struct Config {
port: u16,
}
fn load_config(json: &str) -> Result<Config, serde_json::Error> {
serde_json::from_str(json)
}
fn main() {
let json = r#"{"port": 8080}"#;
match load_config(json) {
Ok(config) => println!("端口: {}", config.port),
Err(e) => eprintln!("解析失败: {}", e),
}
// 错误的JSON
let bad_json = r#"{"port": "not a number"}"#;
if let Err(e) = load_config(bad_json) {
eprintln!("错误: {}", e);
}
}
---
2.3 格式:JSON、TOML、Bincode
01.JSON格式
a.特点
人类可读的文本格式,广泛用于Web API和配置文件。
支持对象、数组、字符串、数字、布尔值和null。
文件体积较大,但兼容性好。
b.代码示例
---
use serde::{Serialize, Deserialize};
use serde_json;
#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
age: u32,
hobbies: Vec<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let person = Person {
name: "Bob".to_string(),
age: 25,
hobbies: vec!["读书".to_string(), "游泳".to_string()],
};
// 序列化为JSON
let json = serde_json::to_string_pretty(&person)?;
println!("JSON:\n{}", json);
// 反序列化
let person2: Person = serde_json::from_str(&json)?;
println!("Person: {:?}", person2);
Ok(())
}
---
02.TOML格式
a.特点
配置文件友好的格式,语法简洁清晰。
支持表、数组、字符串、整数、浮点数、布尔值和日期时间。
常用于Cargo.toml等配置文件。
b.代码示例
---
use serde::{Serialize, Deserialize};
use toml;
#[derive(Serialize, Deserialize, Debug)]
struct Config {
server: ServerConfig,
database: DatabaseConfig,
}
#[derive(Serialize, Deserialize, Debug)]
struct ServerConfig {
host: String,
port: u16,
}
#[derive(Serialize, Deserialize, Debug)]
struct DatabaseConfig {
url: String,
max_connections: u32,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = Config {
server: ServerConfig {
host: "localhost".to_string(),
port: 8080,
},
database: DatabaseConfig {
url: "postgres://localhost/db".to_string(),
max_connections: 10,
},
};
// 序列化为TOML
let toml_str = toml::to_string(&config)?;
println!("TOML:\n{}", toml_str);
// 反序列化
let config2: Config = toml::from_str(&toml_str)?;
println!("Config: {:?}", config2);
Ok(())
}
---
03.Bincode格式
a.特点
二进制格式,体积小,速度快。
不可读,适合内部数据传输和存储。
序列化和反序列化性能优异。
b.代码示例
---
use serde::{Serialize, Deserialize};
use bincode;
#[derive(Serialize, Deserialize, Debug)]
struct Message {
id: u64,
timestamp: u64,
payload: Vec<u8>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let message = Message {
id: 12345,
timestamp: 1234567890,
payload: vec![1, 2, 3, 4, 5],
};
// 序列化为二进制
let bytes = bincode::serialize(&message)?;
println!("Bincode大小: {} 字节", bytes.len());
// 反序列化
let message2: Message = bincode::deserialize(&bytes)?;
println!("Message: {:?}", message2);
Ok(())
}
---
04.格式对比
a.性能对比
Bincode:最快,体积最小,适合性能敏感场景。
JSON:中等速度,体积较大,适合Web API。
TOML:较慢,体积中等,适合配置文件。
b.可读性对比
JSON:可读性好,广泛支持。
TOML:可读性最好,配置文件友好。
Bincode:不可读,仅适合机器处理。
c.使用场景
JSON:Web API、前后端通信、日志记录。
TOML:配置文件、项目设置。
Bincode:内部数据传输、缓存、高性能场景。
05.其他格式
a.MessagePack
a.功能说明
类似JSON的二进制格式,比JSON更紧凑。
b.代码示例
---
use serde::{Serialize, Deserialize};
use rmp_serde;
#[derive(Serialize, Deserialize)]
struct Data {
value: i32,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = Data { value: 42 };
let bytes = rmp_serde::to_vec(&data)?;
let data2: Data = rmp_serde::from_slice(&bytes)?;
Ok(())
}
---
b.YAML
a.功能说明
人类可读的数据序列化格式,支持复杂的数据结构。
b.代码示例
---
use serde::{Serialize, Deserialize};
use serde_yaml;
#[derive(Serialize, Deserialize)]
struct Config {
name: String,
items: Vec<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let config = Config {
name: "test".to_string(),
items: vec!["a".to_string(), "b".to_string()],
};
let yaml = serde_yaml::to_string(&config)?;
println!("{}", yaml);
Ok(())
}
---
2.4 自定义序列化
01.自定义序列化概述
a.定义
当默认的序列化行为不满足需求时,可以手动实现Serialize和Deserialize trait来自定义序列化逻辑。
b.使用场景
特殊格式转换、数据加密、版本兼容、性能优化。
02.实现Serialize trait
a.基本实现
a.功能说明
手动实现Serialize trait,完全控制序列化过程。
b.代码示例
---
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
struct Point {
x: i32,
y: i32,
}
impl Serialize for Point {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("Point", 2)?;
state.serialize_field("x", &self.x)?;
state.serialize_field("y", &self.y)?;
state.end()
}
}
fn main() {
let point = Point { x: 10, y: 20 };
let json = serde_json::to_string(&point).unwrap();
println!("{}", json);
}
---
b.自定义格式
a.功能说明
将数据序列化为特定格式,如将坐标序列化为字符串。
b.代码示例
---
use serde::{Serialize, Serializer};
struct Coordinate {
lat: f64,
lon: f64,
}
impl Serialize for Coordinate {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = format!("{},{}", self.lat, self.lon);
serializer.serialize_str(&s)
}
}
fn main() {
let coord = Coordinate { lat: 39.9, lon: 116.4 };
let json = serde_json::to_string(&coord).unwrap();
println!("{}", json); // "39.9,116.4"
}
---
03.实现Deserialize trait
a.基本实现
a.功能说明
手动实现Deserialize trait,完全控制反序列化过程。
b.代码示例
---
use serde::{Deserialize, Deserializer};
use serde::de::{self, Visitor};
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl<'de> Deserialize<'de> for Point {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PointVisitor;
impl<'de> Visitor<'de> for PointVisitor {
type Value = Point;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Point")
}
fn visit_map<A>(self, mut map: A) -> Result<Point, A::Error>
where
A: de::MapAccess<'de>,
{
let mut x = None;
let mut y = None;
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"x" => x = Some(map.next_value()?),
"y" => y = Some(map.next_value()?),
_ => { map.next_value::<de::IgnoredAny>()?; }
}
}
let x = x.ok_or_else(|| de::Error::missing_field("x"))?;
let y = y.ok_or_else(|| de::Error::missing_field("y"))?;
Ok(Point { x, y })
}
}
deserializer.deserialize_struct("Point", &["x", "y"], PointVisitor)
}
}
---
04.使用serialize_with和deserialize_with
a.字段级自定义
a.功能说明
使用��性标记为特定字段指定自定义序列化函数。
b.代码示例
---
use serde::{Serialize, Deserialize, Serializer, Deserializer};
fn serialize_as_string<S>(value: &u64, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&value.to_string())
}
fn deserialize_from_string<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
s.parse().map_err(serde::de::Error::custom)
}
#[derive(Serialize, Deserialize)]
struct Data {
#[serde(serialize_with = "serialize_as_string")]
#[serde(deserialize_with = "deserialize_from_string")]
id: u64,
name: String,
}
fn main() {
let data = Data {
id: 12345,
name: "test".to_string(),
};
let json = serde_json::to_string(&data).unwrap();
println!("{}", json); // {"id":"12345","name":"test"}
let data2: Data = serde_json::from_str(&json).unwrap();
println!("ID: {}", data2.id);
}
---
05.复杂场景
a.枚举自定义序列化
a.功能说明
为枚举类型实现自定义序列化,支持多种表示形式。
b.代码示例
---
use serde::{Serialize, Deserialize, Serializer, Deserializer};
enum Status {
Active,
Inactive,
Pending,
}
impl Serialize for Status {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
Status::Active => "active",
Status::Inactive => "inactive",
Status::Pending => "pending",
};
serializer.serialize_str(s)
}
}
impl<'de> Deserialize<'de> for Status {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
match s.as_str() {
"active" => Ok(Status::Active),
"inactive" => Ok(Status::Inactive),
"pending" => Ok(Status::Pending),
_ => Err(serde::de::Error::custom("invalid status")),
}
}
}
---
b.版本兼容
a.功能说明
通过自定义反序列化处理不同版本的数据格式。
b.代码示例
---
use serde::{Deserialize, Deserializer};
use serde::de::{self, Visitor};
#[derive(Debug)]
struct Config {
version: u32,
settings: String,
}
impl<'de> Deserialize<'de> for Config {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct ConfigV1 {
settings: String,
}
#[derive(Deserialize)]
struct ConfigV2 {
version: u32,
settings: String,
}
#[derive(Deserialize)]
#[serde(untagged)]
enum ConfigVersion {
V1(ConfigV1),
V2(ConfigV2),
}
match ConfigVersion::deserialize(deserializer)? {
ConfigVersion::V1(v1) => Ok(Config {
version: 1,
settings: v1.settings,
}),
ConfigVersion::V2(v2) => Ok(Config {
version: v2.version,
settings: v2.settings,
}),
}
}
}
---
2.5 derive宏:Serialize、Deserialize
01.derive宏概述
a.定义
derive宏是Rust的过程宏,可以自动为类型生成Serialize和Deserialize trait的实现。
b.优势
零运行时开销:代码在编译时生成。
类型安全:利用Rust类型系统确保正确性。
简洁:一行代码即可实现序列化功能。
02.基本使用
a.简单结构体
a.功能说明
为结构体添加#[derive(Serialize, Deserialize)]即可自动实现序列化。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
active: bool,
}
fn main() {
let user = User {
id: 1,
name: "Alice".to_string(),
active: true,
};
let json = serde_json::to_string(&user).unwrap();
println!("{}", json);
let user2: User = serde_json::from_str(&json).unwrap();
println!("{:?}", user2);
}
---
b.嵌套结构体
a.功能说明
嵌套的结构体也需要实现Serialize和Deserialize。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Address {
street: String,
city: String,
zip: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct Person {
name: String,
age: u32,
address: Address,
}
fn main() {
let person = Person {
name: "Bob".to_string(),
age: 30,
address: Address {
street: "123 Main St".to_string(),
city: "Beijing".to_string(),
zip: "100000".to_string(),
},
};
let json = serde_json::to_string_pretty(&person).unwrap();
println!("{}", json);
}
---
03.支持的类型
a.基本类型
a.功能说明
serde支持所有Rust基本类型的序列化。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct AllTypes {
boolean: bool,
integer: i32,
unsigned: u64,
float: f64,
string: String,
char_val: char,
}
---
b.集合类型
a.功能说明
Vec、HashMap、HashSet等标准库集合类型都支持序列化。
b.代码示例
---
use serde::{Serialize, Deserialize};
use std::collections::HashMap;
#[derive(Serialize, Deserialize, Debug)]
struct Data {
list: Vec<i32>,
map: HashMap<String, String>,
optional: Option<String>,
}
fn main() {
let mut map = HashMap::new();
map.insert("key1".to_string(), "value1".to_string());
let data = Data {
list: vec![1, 2, 3],
map,
optional: Some("test".to_string()),
};
let json = serde_json::to_string_pretty(&data).unwrap();
println!("{}", json);
}
---
04.枚举类型
a.简单枚举
a.功能说明
枚举类型可以直接使用derive宏实现序列化。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
enum Status {
Active,
Inactive,
Pending,
}
#[derive(Serialize, Deserialize, Debug)]
struct Task {
name: String,
status: Status,
}
fn main() {
let task = Task {
name: "任务1".to_string(),
status: Status::Active,
};
let json = serde_json::to_string(&task).unwrap();
println!("{}", json);
}
---
b.���数据的枚举
a.功能说明
枚举变体可以包含数据,serde会自动处理。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
enum Message {
Text(String),
Number(i32),
Coordinates { x: f64, y: f64 },
}
fn main() {
let messages = vec![
Message::Text("Hello".to_string()),
Message::Number(42),
Message::Coordinates { x: 1.0, y: 2.0 },
];
for msg in messages {
let json = serde_json::to_string(&msg).unwrap();
println!("", json);
}
}
---
05.泛型类型
a.泛型结构体
a.功能说明
泛型类型参数需要满足Serialize和Deserialize约束。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Wrapper<T> {
value: T,
metadata: String,
}
fn main() {
let int_wrapper = Wrapper {
value: 42,
metadata: "integer".to_string(),
};
let str_wrapper = Wrapper {
value: "hello".to_string(),
metadata: "string".to_string(),
};
println!("{}", serde_json::to_string(&int_wrapper).unwrap());
println!("{}", serde_json::to_string(&str_wrapper).unwrap());
}
---
b.生命周期参数
a.功能说明
带生命周期参数的类型也可以使用derive宏。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Borrowed<'a> {
text: &'a str,
number: i32,
}
fn main() {
let text = "borrowed string";
let borrowed = Borrowed {
text,
number: 100,
};
let json = serde_json::to_string(&borrowed).unwrap();
println!("{}", json);
}
---
06.限制与注意事项
a.trait约束
所有字段类型必须实现Serialize/Deserialize。
泛型参数需要添加相应的trait约束。
b.不支持的类型
原始指针、函数指针等不支持序列化。
需要使用#[serde(skip)]跳过这些字段。
c.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Data {
value: i32,
#[serde(skip)]
callback: fn() -> i32, // 跳过函数指针
}
---
2.6 属性标记:skip、rename、default
01.skip属性
a.跳过序列化
a.功能说明
使用#[serde(skip)]跳过字段的序列化和反序列化。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct User {
id: u32,
name: String,
#[serde(skip)]
password: String,
}
fn main() {
let user = User {
id: 1,
name: "Alice".to_string(),
password: "secret".to_string(),
};
let json = serde_json::to_string(&user).unwrap();
println!("{}", json); // {"id":1,"name":"Alice"}
}
---
b.skip_serializing和skip_deserializing
a.功能说明
分别控制序列化和反序列化时是否跳过字段。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Data {
value: i32,
#[serde(skip_serializing)]
internal: String,
#[serde(skip_deserializing)]
computed: i32,
}
fn main() {
let data = Data {
value: 42,
internal: "internal".to_string(),
computed: 100,
};
let json = serde_json::to_string(&data).unwrap();
println!("{}", json); // {"value":42,"computed":100}
}
---
02.rename属性
a.重命名字段
a.功能说明
使用#[serde(rename = "new_name")]更改序列化后的字段名。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct ApiResponse {
#[serde(rename = "userId")]
user_id: u32,
#[serde(rename = "userName")]
user_name: String,
#[serde(rename = "isActive")]
is_active: bool,
}
fn main() {
let response = ApiResponse {
user_id: 1,
user_name: "Alice".to_string(),
is_active: true,
};
let json = serde_json::to_string(&response).unwrap();
println!("{}", json);
// {"userId":1,"userName":"Alice","isActive":true}
}
---
b.rename_all属性
a.功能说明
使用#[serde(rename_all = "...")]统一转换所有字段名的命名风格。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct Config {
server_host: String,
server_port: u16,
max_connections: u32,
}
fn main() {
let config = Config {
server_host: "localhost".to_string(),
server_port: 8080,
max_connections: 100,
};
let json = serde_json::to_string(&config).unwrap();
println!("{}", json);
// {"serverHost":"localhost","serverPort":8080,"maxConnections":100}
}
---
03.default属性
a.默认值
a.功能说明
使用#[serde(default)]为缺失的字段提供默认值。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Config {
host: String,
#[serde(default)]
port: u16,
#[serde(default)]
debug: bool,
}
fn main() {
let json = r#"{"host":"localhost"}"#;
let config: Config = serde_json::from_str(json).unwrap();
println!("{:?}", config);
// Config { host: "localhost", port: 0, debug: false }
}
---
b.自定义默认值函数
a.功能说明
使用#[serde(default = "function")]指定自定义默认值函数。
b.代码示例
---
use serde::{Serialize, Deserialize};
fn default_port() -> u16 {
8080
}
fn default_timeout() -> u64 {
30
}
#[derive(Serialize, Deserialize, Debug)]
struct ServerConfig {
host: String,
#[serde(default = "default_port")]
port: u16,
#[serde(default = "default_timeout")]
timeout: u64,
}
fn main() {
let json = r#"{"host":"localhost"}"#;
let config: ServerConfig = serde_json::from_str(json).unwrap();
println!("{:?}", config);
// ServerConfig { host: "localhost", port: 8080, timeout: 30 }
}
---
04.其他常用属性
a.flatten
a.功能说明
使用#[serde(flatten)]将嵌套结构体的字段展平到父结构体中。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Metadata {
created_at: String,
updated_at: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct Document {
id: u32,
title: String,
#[serde(flatten)]
metadata: Metadata,
}
fn main() {
let doc = Document {
id: 1,
title: "文档".to_string(),
metadata: Metadata {
created_at: "2024-01-01".to_string(),
updated_at: "2024-01-02".to_string(),
},
};
let json = serde_json::to_string(&doc).unwrap();
println!("{}", json);
// {"id":1,"title":"文档","created_at":"2024-01-01","updated_at":"2024-01-02"}
}
---
b.tag和content
a.功能说明
用于枚举类型的序列化,控制枚举的表示形式。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
enum Message {
Text { content: String },
Image { url: String },
}
fn main() {
let msg = Message::Text {
content: "Hello".to_string(),
};
let json = serde_json::to_string(&msg).unwrap();
println!("{}", json);
// {"type":"Text","content":"Hello"}
}
---
05.组合使用
a.多个属性组合
a.功能说明
可以在同一个字段上使用多个serde属性。
b.代码示例
---
use serde::{Serialize, Deserialize};
fn default_status() -> String {
"active".to_string()
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
struct User {
user_id: u32,
#[serde(rename = "fullName")]
user_name: String,
#[serde(default = "default_status")]
#[serde(skip_serializing_if = "String::is_empty")]
status: String,
#[serde(skip)]
password: String,
}
fn main() {
let user = User {
user_id: 1,
user_name: "Alice".to_string(),
status: "".to_string(),
password: "secret".to_string(),
};
let json = serde_json::to_string(&user).unwrap();
println!("{}", json);
// {"userId":1,"fullName":"Alice"}
}
---
2.7 生命周期与序列化
01.生命周期概述
a.定义
在序列化过程中,生命周期参数用于处理借用数据,避免不必要的内存分配和复制。
b.使用场景
零拷贝反序列化、借用字符串切片、引用外部数据。
02.借用数据的序列化
a.基本用法
a.功能说明
结构体可以包含借用的数据,如&str,在序列化时直接使用引用。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Message<'a> {
id: u32,
#[serde(borrow)]
content: &'a str,
}
fn main() {
let text = "Hello, World!";
let msg = Message {
id: 1,
content: text,
};
let json = serde_json::to_string(&msg).unwrap();
println!("{}", json);
let msg2: Message = serde_json::from_str(&json).unwrap();
println!("{:?}", msg2);
}
---
b.多个生命周期
a.功能说明
结构体可以包含多个不同生命周期的借用数据。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Data<'a, 'b> {
#[serde(borrow)]
name: &'a str,
#[serde(borrow)]
description: &'b str,
value: i32,
}
fn main() {
let name = "test";
let desc = "description";
let data = Data {
name,
description: desc,
value: 42,
};
let json = serde_json::to_string(&data).unwrap();
println!("{}", json);
}
---
03.零拷贝反序列化
a.概念
a.功能说明
零拷贝反序列化允许直接借用输入数据,而不是复制到新的内存中,提高性能。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Record<'a> {
id: u32,
#[serde(borrow)]
name: &'a str,
#[serde(borrow)]
tags: Vec<&'a str>,
}
fn main() {
let json = r#"{"id":1,"name":"Alice","tags":["rust","serde"]}"#;
let record: Record = serde_json::from_str(json).unwrap();
println!("{:?}", record);
// Record { id: 1, name: "Alice", tags: ["rust", "serde"] }
}
---
b.Cow类型
a.功能说明
使用Cow<str>可以在需要时才进行内存分配,兼顾性能和灵活性。
b.代码示例
---
use serde::{Serialize, Deserialize};
use std::borrow::Cow;
#[derive(Serialize, Deserialize, Debug)]
struct FlexibleData<'a> {
id: u32,
#[serde(borrow)]
name: Cow<'a, str>,
}
fn main() {
// 借用数据
let json1 = r#"{"id":1,"name":"Alice"}"#;
let data1: FlexibleData = serde_json::from_str(json1).unwrap();
println!("{:?}", data1);
// 拥有数据
let data2 = FlexibleData {
id: 2,
name: Cow::Owned("Bob".to_string()),
};
let json2 = serde_json::to_string(&data2).unwrap();
println!("{}", json2);
}
---
04.生命周期约束
a.显式生命周期标注
a.功能说明
在复杂场景中需要显式标注生命周期参数。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Container<'a> {
#[serde(borrow)]
items: Vec<Item<'a>>,
}
#[derive(Serialize, Deserialize, Debug)]
struct Item<'a> {
#[serde(borrow)]
name: &'a str,
value: i32,
}
fn main() {
let json = r#"{"items":[{"name":"item1","value":10},{"name":"item2","value":20}]}"#;
let container: Container = serde_json::from_str(json).unwrap();
println!("{:?}", container);
}
---
b.静态生命周期
a.功能说明
使用'static生命周期表示数据在整个程序运行期间都有效。
b.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize, Debug)]
struct Config {
name: &'static str,
version: &'static str,
}
fn main() {
let config = Config {
name: "MyApp",
version: "1.0.0",
};
let json = serde_json::to_string(&config).unwrap();
println!("{}", json);
}
---
05.性能优化
a.避免不必要的复制
a.功能说明
通过使用借用数据和零拷贝反序列化,可以显著提高性能。
b.代码示例
---
use serde::{Serialize, Deserialize};
use std::time::Instant;
#[derive(Serialize, Deserialize)]
struct OwnedData {
text: String,
}
#[derive(Serialize, Deserialize)]
struct BorrowedData<'a> {
#[serde(borrow)]
text: &'a str,
}
fn main() {
let json = r#"{"text":"very long string..."}"#;
// 拥有数据的反序列化(需要复制)
let start = Instant::now();
for _ in 0..10000 {
let _: OwnedData = serde_json::from_str(json).unwrap();
}
println!("拥有数据: {:?}", start.elapsed());
// 借用数据的反序列化(零拷贝)
let start = Instant::now();
for _ in 0..10000 {
let _: BorrowedData = serde_json::from_str(json).unwrap();
}
println!("借用数据: {:?}", start.elapsed());
}
---
b.选择合适的类型
a.功能说明
根据使用场景选择String、&str或Cow<str>。
b.使用建议
String:需要拥有数据或修改数据时使用。
&str:只读数据且生命周期明确时使用。
Cow<str>:需要灵活处理拥有和借用数据时使用。
06.常见问题
a.生命周期冲突
当借用数据的生命周期不够长时,需要使用String拥有数据。
b.反序列化失败
零拷贝反序列化要求输入数据在反序列化对象的整个生命周期内有效。
c.代码示例
---
use serde::{Serialize, Deserialize};
#[derive(Deserialize)]
struct Data<'a> {
#[serde(borrow)]
text: &'a str,
}
fn parse_data() -> Data<'static> {
let json = r#"{"text":"hello"}"#.to_string();
// 错误:json的生命周期不够长
// serde_json::from_str(&json).unwrap()
// 正确:使用String拥有数据
#[derive(Deserialize)]
struct OwnedData {
text: String,
}
let owned: OwnedData = serde_json::from_str(&json).unwrap();
// 转换为静态生命周期需要特殊处理
unimplemented!()
}
---
3 异步IO
3.1 概念:async/await
01.异步编程概述
a.定义
异步编程允许程序在等待IO操作完成时执行其他任务,提高并发性和资源利用率。
b.核心概念
Future:表示一个可能尚未完成的异步计算。
async:将函数标记为异步函数,返回Future。
await:等待Future完成并获取结果。
Runtime:执行异步任务的运行时环境。
02.async关键字
a.基本用法
a.功能说明
使用async关键字定义异步函数,函数返回impl Future。
b.代码示例
---
async fn hello() -> String {
"Hello, async!".to_string()
}
#[tokio::main]
async fn main() {
let result = hello().await;
println!("{}", result);
}
---
b.异步块
a.功能说明
使用async块创建匿名的异步代码块。
b.代码示例
---
#[tokio::main]
async fn main() {
let future = async {
println!("异步块开始");
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
println!("异步块结束");
42
};
let result = future.await;
println!("结果: {}", result);
}
---
03.await关键字
a.基本用法
a.功能说明
await用于等待Future完成,只能在async函数或块中使用。
b.代码示例
---
use tokio::time::{sleep, Duration};
async fn task1() {
println!("任务1开始");
sleep(Duration::from_secs(2)).await;
println!("任务1完成");
}
async fn task2() {
println!("任务2开始");
sleep(Duration::from_secs(1)).await;
println!("任务2完成");
}
#[tokio::main]
async fn main() {
task1().await;
task2().await;
}
---
b.并发执行
a.功能说明
使用tokio::join!或tokio::spawn实现多个Future的并发执行。
b.代码示例
---
use tokio::time::{sleep, Duration};
async fn task1() -> i32 {
sleep(Duration::from_secs(2)).await;
1
}
async fn task2() -> i32 {
sleep(Duration::from_secs(1)).await;
2
}
#[tokio::main]
async fn main() {
let (r1, r2) = tokio::join!(task1(), task2());
println!("结果: + {} = {}", r1, r2, r1 + r2);
}
---
04.Future trait
a.定义
a.功能说明
Future是异步计算的核心trait,定义了poll方法用于推进计算。
b.代码示例
---
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyFuture {
value: i32,
}
impl Future for MyFuture {
type Output = i32;
fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
Poll::Ready(self.value)
}
}
#[tokio::main]
async fn main() {
let future = MyFuture { value: 42 };
let result = future.await;
println!("结果: {}", result);
}
---
05.错误处理
a.Result与async
a.功能说明
异步函数可以返回Result类型,使用?运算符传播错误。
b.代码示例
---
use std::io;
async fn read_file() -> io::Result<String> {
tokio::fs::read_to_string("data.txt").await
}
async fn process() -> io::Result<()> {
let content = read_file().await?;
println!("内容: {}", content);
Ok(())
}
#[tokio::main]
async fn main() {
match process().await {
Ok(_) => println!("成功"),
Err(e) => eprintln!("错误: {}", e),
}
}
---
3.2 运行时:tokio、async-std
01.运行时概述
a.定义
异步运行时负责调度和执行异步任务,提供事件循环、任务调度器和IO驱动。
b.主要运行时
tokio:功能最全面,生态最丰富,性能优异。
async-std:API设计类似标准库,易于学习。
02.tokio运行时
a.基本使用
a.功能说明
使用#[tokio::main]宏快速启动tokio运行时。
b.代码示例
---
#[tokio::main]
async fn main() {
println!("tokio运行时启动");
}
---
b.手动构建
a.功能说明
使用Runtime::new()手动创建运行时。
b.代码示例
---
use tokio::runtime::Runtime;
fn main() {
let rt = Runtime::new().unwrap();
rt.block_on(async {
println!("异步任务");
});
}
---
03.async-std运行时
a.基本使用
a.功能说明
async-std提供类似标准库的API。
b.代码示例
---
#[async_std::main]
async fn main() {
println!("async-std启动");
}
---
3.3 异步读写:AsyncRead、AsyncWrite
01.AsyncRead trait
a.定义
AsyncRead是异步版本的Read trait,用于异步读取数据。
b.代码示例
---
use tokio::io::{AsyncReadExt, BufReader};
use tokio::fs::File;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let file = File::open("data.txt").await?;
let mut reader = BufReader::new(file);
let mut contents = String::new();
reader.read_to_string(&mut contents).await?;
println!("{}", contents);
Ok(())
}
---
02.AsyncWrite trait
a.定义
AsyncWrite是异步版本的Write trait,用于异步写入数据。
b.代码示例
---
use tokio::io::AsyncWriteExt;
use tokio::fs::File;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let mut file = File::create("output.txt").await?;
file.write_all(b"Hello, async!").await?;
file.flush().await?;
Ok(())
}
---
3.4 异步文件操作
01.读取文件
a.功能说明
使用tokio::fs模块进行异步文件操作。
b.代码示例
---
use tokio::fs;
#[tokio::main]
async fn main() -> std::io::Result<()> {
let contents = fs::read_to_string("config.txt").await?;
println!("{}", contents);
Ok(())
}
---
02.写入文件
a.功能说明
异步写入文件内容。
b.代码示例
---
use tokio::fs;
#[tokio::main]
async fn main() -> std::io::Result<()> {
fs::write("output.txt", b"data").await?;
Ok(())
}
---
3.5 异步网络IO
01.TCP连接
a.功能说明
使用tokio::net进行异步TCP通信。
b.代码示例
---
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
let n = socket.read(&mut buf).await.unwrap();
socket.write_all(&buf[0..n]).await.unwrap();
});
}
}
---
3.6 Future与Poll
01.Future trait
a.定义
Future表示一个异步计算��通过poll方法推进执行。
b.代码示例
---
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyFuture;
impl Future for MyFuture {
type Output = i32;
fn poll(self: Pin<&mut Self>, _: &mut Context) -> Poll<i32> {
Poll::Ready(42)
}
}
---
02.Poll状态
a.Ready
表示Future已完成,返回结果。
b.Pending
表示Future尚未完成,需要稍后再次poll。
4 网络编程
4.1 TCP:TcpListener、TcpStream
01.TCP服务器
a.功能说明
使用TcpListener监听TCP连接。
b.代码示例
---
use std::net::TcpListener;
use std::io::{Read, Write};
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080")?;
for stream in listener.incoming() {
let mut stream = stream?;
let mut buffer = [0; 1024];
stream.read(&mut buffer)?;
stream.write_all(b"HTTP/1.1 200 OK\r\n\r\n")?;
}
Ok(())
}
---
02.TCP客户端
a.功能说明
使用TcpStream连接TCP服务器。
b.代码示例
---
use std::net::TcpStream;
use std::io::{Read, Write};
fn main() -> std::io::Result<()> {
let mut stream = TcpStream::connect("127.0.0.1:8080")?;
stream.write_all(b"GET / HTTP/1.1\r\n\r\n")?;
let mut response = String::new();
stream.read_to_string(&mut response)?;
println!("{}", response);
Ok(())
}
---
4.2 UDP:UdpSocket
01.UDP通信
a.功能说明
使用UdpSocket进行UDP通信。
b.代码示例
---
use std::net::UdpSocket;
fn main() -> std::io::Result<()> {
let socket = UdpSocket::bind("127.0.0.1:8080")?;
let mut buf = [0; 1024];
let (amt, src) = socket.recv_from(&mut buf)?;
socket.send_to(&buf[..amt], src)?;
Ok(())
}
---
4.3 异步网络:tokio::net
01.异步TCP
a.功能说明
使用tokio::net进行异步TCP通信。
b.代码示例
---
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = vec![0; 1024];
socket.read(&mut buf).await.unwrap();
socket.write_all(b"Response").await.unwrap();
});
}
}
---
4.4 HTTP客户端:reqwest
01.GET请求
a.功能说明
使用reqwest发送HTTP GET请求。
b.代码示例
---
use reqwest;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let body = reqwest::get("https://www.rust-lang.org")
.await?
.text()
.await?;
println!("{}", body);
Ok(())
}
---
02.POST请求
a.功能说明
发送POST请求并携带JSON数据。
b.代码示例
---
use reqwest;
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let client = reqwest::Client::new();
let res = client.post("https://api.example.com/data")
.json(&json!({"key": "value"}))
.send()
.await?;
println!("{}", res.text().await?);
Ok(())
}
---
4.5 HTTP服务器:axum、actix-web
01.axum框架
a.功能说明
axum是基于tokio的Web框架。
b.代码示例
---
use axum::{routing::get, Router};
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(|| async { "Hello, World!" }));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
---
02.actix-web框架
a.功能说明
actix-web是高性能的Web框架。
b.代码示例
---
use actix_web::{web, App, HttpServer, Responder};
async fn index() -> impl Responder {
"Hello, World!"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new().route("/", web::get().to(index))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
---
4.6 WebSocket
01.WebSocket服务器
a.功能说明
使用tokio-tungstenite实现WebSocket服务器。
b.代码示例
---
use tokio::net::TcpListener;
use tokio_tungstenite::accept_async;
use futures_util::{StreamExt, SinkExt};
#[tokio::main]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(async move {
let ws_stream = accept_async(stream).await.unwrap();
let (mut write, mut read) = ws_stream.split();
while let Some(msg) = read.next().await {
let msg = msg.unwrap();
write.send(msg).await.unwrap();
}
});
}
}
---
5 高级特性
5.1 零拷贝
01.概念
a.定义
零拷贝技术避免数据在内存中的多次复制,提高IO性能。
b.实现方式
使用sendfile系统调用、内存映射、直接缓冲区等技术。
02.代码示例
a.功能说明
使用std::io::copy实现零拷贝文件传输。
b.代码示例
---
use std::fs::File;
use std::io;
fn main() -> io::Result<()> {
let mut input = File::open("input.txt")?;
let mut output = File::create("output.txt")?;
io::copy(&mut input, &mut output)?;
Ok(())
}
---
5.2 内存映射:mmap
01.内存映射文件
a.功能说明
使用memmap2库进行内存映射文件操作。
b.代码示例
---
use memmap2::MmapOptions;
use std::fs::File;
fn main() -> std::io::Result<()> {
let file = File::open("data.bin")?;
let mmap = unsafe { MmapOptions::new().map(&file)? };
println!("文件大小: {}", mmap.len());
Ok(())
}
---
5.3 管道:pipe
01.管道通信
a.功能说明
使用std::process::Command创建管道进行进程间通信。
b.代码示例
---
use std::process::{Command, Stdio};
use std::io::Write;
fn main() -> std::io::Result<()> {
let mut child = Command::new("cat")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
child.stdin.as_mut().unwrap().write_all(b"Hello")?;
let output = child.wait_with_output()?;
println!("{}", String::from_utf8_lossy(&output.stdout));
Ok(())
}
---
5.4 错误处理:io::Error、Result
01.io::Error
a.定义
io::Error表示IO操作中的错误。
b.代码示例
---
use std::fs::File;
use std::io;
fn main() {
match File::open("missing.txt") {
Ok(_) => println!("文件打开成功"),
Err(e) => match e.kind() {
io::ErrorKind::NotFound => println!("文件不存在"),
io::ErrorKind::PermissionDenied => println!("权限不足"),
_ => println!("其他错误: {}", e),
},
}
}
---
02.Result类型
a.功能说明
使用Result<T, io::Error>处理IO操作的返回值。
b.代码示例
---
use std::fs;
use std::io;
fn read_file(path: &str) -> io::Result<String> {
fs::read_to_string(path)
}
fn main() {
match read_file("data.txt") {
Ok(content) => println!("{}", content),
Err(e) => eprintln!("错误: {}", e),
}
}
---
5.5 路径操作:Path、PathBuf
01.Path类型
a.定义
Path是路径的切片类型,类似于str。
b.代码示例
---
use std::path::Path;
fn main() {
let path = Path::new("/usr/local/bin");
println!("父目录: {:?}", path.parent());
println!("文件名: {:?}", path.file_name());
println!("扩展名: {:?}", path.extension());
}
---
02.PathBuf类型
a.定义
PathBuf是拥有所有权的路径类型,类似于String。
b.代码示例
---
use std::path::PathBuf;
fn main() {
let mut path = PathBuf::from("/usr");
path.push("local");
path.push("bin");
path.set_extension("txt");
println!("{:?}", path);
}
---
5.6 目录遍历:read_dir、WalkDir
01.read_dir
a.功能说明
使用fs::read_dir遍历目录中的条目。
b.代码示例
---
use std::fs;
fn main() -> std::io::Result<()> {
for entry in fs::read_dir(".")? {
let entry = entry?;
println!("{:?}", entry.path());
}
Ok(())
}
---
02.WalkDir
a.功能说明
使用walkdir库递归遍历目录树。
b.代码示例
---
use walkdir::WalkDir;
fn main() {
for entry in WalkDir::new(".") {
let entry = entry.unwrap();
println!("{}", entry.path().display());
}
}
---