You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust Rocket框架修改State报错E0596的解决方法及咨询

Rocket框架中State类型无法修改的解决方案

问题背景

使用Rocket 0.5.0-rc.3框架时,尝试通过State类型存储服务器状态并修改其中的数据,遇到以下编译错误:

error[E0596]: cannot borrow data in dereference of `rocket::State<FunnyDatabase>` as mutable
 --> src\routes.rs:9:25
  |
9 |     if let Some(room) = rooms.0.iter_mut().find(|room| room.name == room_id) {
  |                         ^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
  |
  = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `rocket::State<FunnyDatabase>`

相关代码片段

路由函数:

#[post("/join_room/<room_id>/<player_name>")]
pub fn join_room(room_id: String, player_name: String, rooms: &State<FunnyDatabase>) -> (Status, (ContentType, String)) { 
    if let Some(room) = rooms.0.iter_mut().find(|room| room.name == room_id) {
        room.players.push_back(Player{ name: player_name.clone(), card: "UNKNOWN".to_string() });
    }
...

模拟数据库结构体:

pub struct FunnyDatabase(pub LinkedList<Room>);

State初始化代码:

rocket::build()
    .manage(FunnyDatabase(LinkedList::<Room>::new()))
...

Room结构体定义:

pub struct Room {
    pub name: String,
    pub players: LinkedList<Player>
}

问题原因

Rocket的State<T>提供的是不可变引用,设计目的是保证多线程/异步环境下的安全读取,因此不允许直接修改其内部数据。要实现可修改的全局状态,必须在FunnyDatabase内部封装线程安全的可变容器。

解决方案

方案1:使用std::sync::Mutex(同步场景)

适用于同步路由或对性能要求不高的场景:

  1. 修改FunnyDatabase结构体,用Mutex包裹LinkedList:
use std::sync::Mutex;
use std::collections::LinkedList;

pub struct FunnyDatabase(pub Mutex<LinkedList<Room>>);
  1. 更新State初始化代码:
rocket::build()
    .manage(FunnyDatabase(Mutex::new(LinkedList::<Room>::new())))
  1. 修改路由函数,获取锁后再修改数据:
#[post("/join_room/<room_id>/<player_name>")]
pub fn join_room(room_id: String, player_name: String, rooms: &State<FunnyDatabase>) -> (Status, (ContentType, String)) { 
    // 获取Mutex锁,实际项目建议处理PoisonError(锁被panic线程持有)
    let mut rooms_list = rooms.0.lock().unwrap();
    
    if let Some(room) = rooms_list.iter_mut().find(|room| room.name == room_id) {
        room.players.push_back(Player{ name: player_name.clone(), card: "UNKNOWN".to_string() });
    }

    // 示例返回,根据实际需求调整
    (Status::Ok, (ContentType::Json, "{\"status\": \"success\"}".to_string()))
}

方案2:使用tokio::sync::RwLock(异步场景推荐)

Rocket 0.5默认是异步框架,使用tokio::sync::RwLock可以避免阻塞线程,提升并发性能:

  1. 修改FunnyDatabase结构体:
use tokio::sync::RwLock;
use std::collections::LinkedList;

pub struct FunnyDatabase(pub RwLock<LinkedList<Room>>);
  1. 更新State初始化代码:
rocket::build()
    .manage(FunnyDatabase(RwLock::new(LinkedList::<Room>::new())))
  1. 修改路由函数为异步,并通过await获取写锁:
#[post("/join_room/<room_id>/<player_name>")]
pub async fn join_room(room_id: String, player_name: String, rooms: &State<FunnyDatabase>) -> (Status, (ContentType, String)) { 
    // 获取写锁
    let mut rooms_list = rooms.0.write().await;
    
    if let Some(room) = rooms_list.iter_mut().find(|room| room.name == room_id) {
        room.players.push_back(Player{ name: player_name.clone(), card: "UNKNOWN".to_string() });
    }

    // 示例返回,根据实际需求调整
    (Status::Ok, (ContentType::Json, "{\"status\": \"success\"}".to_string()))
}

总结

Rocket的State本身不支持直接修改,必须通过内部封装线程安全的可变类型(如Mutex/RwLock)来实现全局状态的安全修改,适配同步或异步的业务场景。

内容的提问来源于stack exchange,提问作者Perwell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 08:57:50