如何在Rust中可变共享单个结构体实例给多个消费者(如服务)
要在Rust中实现和你给出的TypeScript示例功能一致、且线程安全的计数器HTTP API,核心要解决的是多请求间共享可变状态的问题,Rust标准库提供了对应的线程安全工具组合:Arc负责多线程下的对象所有权共享,Mutex负责互斥访问内部数据,自动实现你需要的加锁逻辑。
我们选用Rust生态常用的axum Web框架来对应express的能力,完整实现如下:
第一步:配置依赖
Cargo.toml内容:
[package] name = "counter-demo" version = "0.1.0" edition = "2021" [dependencies] axum = "0.7" tokio = { version = "1", features = ["full"] }
第二步:实现业务逻辑
src/main.rs内容:
use axum::{ http::StatusCode, response::IntoResponse, routing::{get, post}, Router, State, }; use std::sync::{Arc, Mutex}; // 计数器服务定义和你给出的示例一致 struct CounterService { value: i32, } impl CounterService { fn new() -> Self { Self { value: 0 } } fn increment(&mut self) { self.value += 1; } fn decrement(&mut self) { self.value -= 1; } } // 定义共享状态类型,简化后续代码 type SharedCounter = Arc<Mutex<CounterService>>; // GET /value 处理器,只读访问计数器 async fn get_value(State(counter): State<SharedCounter>) -> impl IntoResponse { let inner = counter.lock().unwrap(); inner.value.to_string() } // POST /increment 处理器,修改计数器 async fn increment(State(counter): State<SharedCounter>) -> impl IntoResponse { let mut inner = counter.lock().unwrap(); inner.increment(); StatusCode::NO_CONTENT } // POST /decrement 处理器,修改计数器 async fn decrement(State(counter): State<SharedCounter>) -> impl IntoResponse { let mut inner = counter.lock().unwrap(); inner.decrement(); StatusCode::NO_CONTENT } #[tokio::main] async fn main() { // 初始化共享状态,把计数器包裹在Arc和Mutex中 let shared_counter = Arc::new(Mutex::new(CounterService::new())); // 构建路由、绑定状态,和express的路由注册逻辑对应 let app = Router::new() .route("/value", get(get_value)) .route("/increment", post(increment)) .route("/decrement", post(decrement)) .with_state(shared_counter); // 启动服务监听3000端口 let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); }
逻辑说明
你提到的三个handler共享状态的需求完全被覆盖:
Arc保证三个handler可以同时持有计数器的引用,不需要拷贝实例Mutex自动处理所有读写操作的加锁逻辑,天生线程安全,不会出现竞态条件- 只读和修改操作的权限完全由Rust的借用规则和Mutex机制保证,不会出现并发修改冲突
内容的提问来源于stack exchange,提问作者David Alsh
相关产品推荐
相关产品推荐

