第一篇: Rust 基础概念速查表

52 阅读8分钟

Rust 基础概念速查表

本文档为 Rust 新手提供项目中常见概念的快速参考。

目录

  1. 基础语法
  2. 所有权系统
  3. 类型系统
  4. 错误处理
  5. 异步编程
  6. 常用宏
  7. 项目中的实例

基础语法

变量声明

// 不可变变量(默认)
let x = 5;
// x = 6;  // 错误!不可变变量不能重新赋值

// 可变变量
let mut y = 5;
y = 6;  // 正确

// 类型标注
let z: i32 = 7;

// 常量(必须标注类型,编译时确定)
const MAX_POINTS: u32 = 100_000;

函数

// 普通函数
fn add(a: i32, b: i32) -> i32 {
    a + b  // 最后一个表达式是返回值(不需要 return)
}

// 带 return 的写法
fn add2(a: i32, b: i32) -> i32 {
    return a + b;  // 显式 return
}

// 无返回值(返回单元类型 ())
fn print_hello() {
    println!("Hello!");
}

// 等价于
fn print_hello2() -> () {
    println!("Hello!");
}

结构体

// 定义结构体
struct User {
    username: String,
    email: String,
    age: u32,
}

// 实例化
let user = User {
    username: String::from("alice"),
    email: String::from("alice@example.com"),
    age: 25,
};

// 访问字段
println!("{}", user.username);

// 为结构体实现方法
impl User {
    // 关联函数(类似静态方法)
    fn new(username: String, email: String) -> Self {
        Self {
            username,
            email,
            age: 18,  // 默认值
        }
    }
    
    // 实例方法
    fn greet(&self) {
        println!("Hello, {}!", self.username);
    }
    
    // 可变方法
    fn set_age(&mut self, age: u32) {
        self.age = age;
    }
}

// 使用
let user = User::new(String::from("bob"), String::from("bob@example.com"));
user.greet();

所有权系统

Rust 最独特和重要的特性,保证内存安全。

三条规则

  1. 每个值都有一个所有者
  2. 同一时间只能有一个所有者
  3. 所有者离开作用域时,值被丢弃

所有权转移(Move)

let s1 = String::from("hello");
let s2 = s1;  // s1 的所有权转移给 s2

// println!("{}", s1);  // 错误!s1 已经失效
println!("{}", s2);  // 正确

借用(Borrowing)

let s1 = String::from("hello");

// 不可变借用(可以有多个)
let r1 = &s1;
let r2 = &s1;
println!("{} and {}", r1, r2);

// 可变借用(同时只能有一个)
let mut s2 = String::from("hello");
let r3 = &mut s2;
r3.push_str(" world");
// let r4 = &mut s2;  // 错误!不能同时有两个可变借用

项目中的例子

// config/database.rs
pub async fn create_pool(database_url: &str) -> Result<MySqlPool, sqlx::Error> {
    //                                   ^^^^ 借用,不获取所有权
    MySqlPoolOptions::new()
        .connect(database_url)  // 可以使用借用的值
        .await
}

// main.rs
let db = database::create_pool(&config.database_url).await?;
//                               ^^^ 传递借用
// config.database_url 仍然有效

类型系统

基本类型

// 整数
let a: i32 = 42;      // 32位有符号整数
let b: u64 = 100;     // 64位无符号整数
let c: isize = 10;    // 指针大小的有符号整数

// 浮点数
let d: f64 = 3.14;    // 64位浮点数

// 布尔值
let e: bool = true;

// 字符
let f: char = 'A';    // Unicode 字符

// 字符串
let s1: &str = "hello";           // 字符串切片(不可变)
let s2: String = String::from("hello");  // 可增长字符串

Option 类型

表示值可能存在或不存在,避免空指针。

// 定义
enum Option<T> {
    Some(T),  // 有值
    None,     // 无值
}

// 使用
let some_number: Option<i32> = Some(5);
let no_number: Option<i32> = None;

// 匹配
match some_number {
    Some(n) => println!("数字是: {}", n),
    None => println!("没有数字"),
}

// if let 简化
if let Some(n) = some_number {
    println!("数字是: {}", n);
}

// unwrap_or 提供默认值
let value = some_number.unwrap_or(0);

Result 类型

表示操作可能成功或失败。

// 定义
enum Result<T, E> {
    Ok(T),   // 成功
    Err(E),  // 失败
}

// 使用
fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 {
        Err(String::from("除数不能为0"))
    } else {
        Ok(a / b)
    }
}

// 匹配处理
match divide(10.0, 2.0) {
    Ok(result) => println!("结果: {}", result),
    Err(err) => println!("错误: {}", err),
}

// ? 操作符(自动传播错误)
fn my_function() -> Result<(), String> {
    let result = divide(10.0, 0.0)?;  // 如果是 Err,提前返回
    println!("结果: {}", result);
    Ok(())
}

错误处理

? 操作符

// 展开前
fn read_file() -> Result<String, std::io::Error> {
    let f = File::open("file.txt");
    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };
    
    let mut contents = String::new();
    match f.read_to_string(&mut contents) {
        Ok(_) => Ok(contents),
        Err(e) => Err(e),
    }
}

// 使用 ? 简化
fn read_file() -> Result<String, std::io::Error> {
    let mut f = File::open("file.txt")?;  // 如果失败,自动返回 Err
    let mut contents = String::new();
    f.read_to_string(&mut contents)?;     // 同上
    Ok(contents)
}

项目中的例子

// config/database.rs
pub async fn init_database(pool: &MySqlPool) -> Result<(), sqlx::Error> {
    sqlx::query("CREATE TABLE...")
        .execute(pool)
        .await?;  // 如果失败,返回错误
    
    Ok(())  // 成功,返回空
}

// main.rs
database::init_database(&db).await?;
// 如果失败,main 函数返回错误,程序退出

异步编程

async/await 基础

// 异步函数
async fn fetch_data() -> String {
    // 模拟异步操作
    tokio::time::sleep(Duration::from_secs(1)).await;
    String::from("data")
}

// 调用异步函数
#[tokio::main]
async fn main() {
    let data = fetch_data().await;  // .await 等待完成
    println!("{}", data);
}

为什么需要异步?

// 同步代码(阻塞)
fn fetch_user() -> User {
    // 等待数据库查询(阻塞线程)
    let user = db.query("SELECT...").execute();
    user
}

// 异步代码(非阻塞)
async fn fetch_user() -> User {
    // 等待数据库查询(不阻塞线程,可以处理其他任务)
    let user = db.query("SELECT...").execute().await;
    user
}

项目中的例子

// services/user_service.rs
pub async fn create_user(&self, payload: CreateUserRequest) -> Result<User> {
    // 异步数据库操作
    let result = sqlx::query(...)
        .execute(&self.db)
        .await?;  // await 等待数据库响应
    
    let user_id = result.6917333 as i64;
    
    // 异步查询
    let user = sqlx::query_as::<_, User>(...)
        .fetch_one(&self.db)
        .await?;  // 再次等待
    
    Ok(user)
}

常用宏

println! / format!

// 打印
println!("Hello, world!");
println!("x = {}", x);  // 格式化
println!("x = {:?}", complex_struct);  // Debug 格式

// 字符串格式化
let s = format!("x = {}, y = {}", x, y);

vec!

// 创建向量(动态数组)
let v = vec![1, 2, 3, 4, 5];

derive

// 自动实现 trait
#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
    name: String,
    age: u32,
}

// 等价于手动实现
impl Debug for User { ... }
impl Clone for User { ... }
impl Serialize for User { ... }
impl Deserialize for User { ... }

项目中的实例

1. 结构体和方法

// config/app_state.rs

// 定义结构体
#[derive(Clone)]
pub struct AppState {
    pub db: MySqlPool,      // 字段:数据库连接池
    pub cache: RedisCache,  // 字段:Redis 缓存
}

// 实现方法
impl AppState {
    // 关联函数(类似构造函数)
    pub fn new(db: MySqlPool, cache: RedisCache) -> Self {
        Self { db, cache }
    }
}

// 使用
let state = AppState::new(db, cache);

2. 所有权和借用

// config/database.rs

// 借用参数(不获取所有权)
pub async fn create_pool(database_url: &str) -> Result<MySqlPool> {
    //                                   ^^^^ 借用
    MySqlPoolOptions::new()
        .connect(database_url)  // 使用借用的值
        .await
}

// main.rs
let config = Config::from_env();
let db = database::create_pool(&config.database_url).await?;
//                               ^^^ 传递借用
// config 仍然有效,可以继续使用

3. Option 和模式匹配

// services/user_service.rs

pub async fn get_user(&self, user_id: i64) -> Result<Option<User>> {
    // 查询可能返回 None(用户不存在)
    let user = sqlx::query_as::<_, User>(...)
        .fetch_optional(&self.db)  // 返回 Option<User>
        .await?;
    
    // if let 匹配 Some
    if let Some(ref u) = user {
        // 用户存在,缓存它
        let user_json = serde_json::to_string(u)?;
        self.cache.set(...).await;
    }
    
    Ok(user)  // 返回 Option<User>
}

// controllers/user_controller.rs

// 模式匹配
match user_service.get_user(user_id).await {
    Ok(Some(user)) => {
        // 找到用户
        Ok((StatusCode::OK, Json(user.into())))
    }
    Ok(None) => {
        // 用户不存在
        Err((StatusCode::NOT_FOUND, Json(json!({"error": "User not found"}))))
    }
    Err(e) => {
        // 数据库错误
        Err((StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": e.to_string()}))))
    }
}

4. Result 和 ? 操作符

// services/user_service.rs

pub async fn create_user(&self, payload: CreateUserRequest) -> Result<User> {
    // ? 自动处理错误
    let result = sqlx::query(...)
        .execute(&self.db)
        .await?;  // 如果失败,提前返回 Err
    
    let user_id = result.6917333 as i64;
    
    let user = sqlx::query_as::<_, User>(...)
        .fetch_one(&self.db)
        .await?;  // 再次使用 ?
    
    Ok(user)  // 成功,返回 Ok(user)
}

5. 异步编程

// main.rs

#[tokio::main]  // 宏:创建异步运行时
async fn main() -> anyhow::Result<()> {
    // 异步操作
    let db = database::create_pool(...).await?;
    //                                   ^^^^^^ await 等待完成
    
    let cache = RedisCache::new(...).await?;
    //                               ^^^^^^ await 等待完成
    
    // 启动服务器(永久运行)
    axum::Server::bind(...)
        .serve(...)
        .await?;  // await 等待服务器关闭
    
    Ok(())
}

6. trait 和泛型

// models/user.rs

// From trait:类型转换
impl From<User> for UserResponse {
    fn from(user: User) -> Self {
        UserResponse {
            id: user.id,
            username: user.username,
            email: user.email,
            created_at: user.created_at,
            updated_at: user.updated_at,
        }
    }
}

// 使用
let user: User = fetch_from_db();
let response: UserResponse = user.into();  // 调用 from

学习建议

  1. 从简单开始

    • 先理解基本语法(变量、函数、结构体)
    • 再学习所有权系统
    • 最后学习异步编程
  2. 阅读代码顺序

    • main.rs → 了解程序入口
    • config/ → 了解配置管理
    • models/ → 了解数据结构
    • utils/ → 了解工具函数
    • services/ → 了解业务逻辑
    • controllers/ → 了解请求处理
    • routes/ → 了解路由配置
  3. 动手实践

    • 修改现有代码
    • 添加新功能
    • 观察编译器错误信息(Rust 编译器非常友好)
  4. 参考资源


常见问题

Q: 为什么有时用 & 有时不用?

A: & 表示借用,不获取所有权。使用场景:

  • 函数参数通常用借用(除非需要所有权)
  • 查看数据用借用
  • 修改数据用可变借用 &mut
  • 转移所有权时不用 &

Q: Clone 的成本高吗?

A: 取决于类型:

  • 简单类型(i32, f64等):Copy trait,成本低
  • String: 完全复制,成本较高
  • MySqlPool, RedisCache: 使用 Arc,clone 只增加引用计数,成本低

Q: async/await 和 sync 有什么区别?

A:

  • 同步:线程等待操作完成(阻塞)
  • 异步:线程不等待,可以处理其他任务(非阻塞)
  • 异步更高效,特别是 I/O 密集型应用

Q: Option 和 Result 什么时候用?

A:

  • Option:表示值可能不存在(类似 nullable)
  • Result:表示操作可能失败(带错误信息)

祝你学习愉快!如有疑问,请参考注释或 Rust 官方文档。