英文:
Unexplained trait bound no longer satisfied when modifying Axum handler body
问题
以下是您提供的Rust代码的翻译:
最近,我开始学习Rust,以使用Axum构建一些简单的Web应用程序。但是,在构建应用程序时出现了一个无法解释的错误,我无法找到其原因。
无法构建的应用程序代码如下所示:
```rust
use axum::{
body::{Body, boxed, StreamBody},
Extension,
http::Request,
response::Response,
Router,
routing::get,
};
use std::{
path::PathBuf,
sync::{Arc, RwLock},
};
type Cache = Arc<RwLock<PathBuf>>;
async fn handle_proxy(
cache: Extension<Cache>,
req: Request<Body>,
) -> Response {
let cache = cache.read().unwrap();
if let Some(object_key) = req.uri().path().rsplitn(2, '/').next() {
// 后续将使用cache变量构建给定的路径
let file = tokio::fs::File::open("/tmp/testaroo").await;
let buf_reader = tokio::io::BufReader::new(file.unwrap());
let stream = tokio_util::io::ReaderStream::new(buf_reader);
return Response::builder().body(boxed(StreamBody::new(stream))).unwrap();
}
// 此处未完全构建该函数,稍后将添加更多代码,不必演示错误。
Response::builder().body(boxed("".to_string())).unwrap()
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/:key", get(handle_proxy));
let addr = "0.0.0.0:8080";
axum::Server::bind(&addr.parse().unwrap()).serve(app.into_make_service()).await.unwrap();
}
关于您提到的错误,问题似乎出现在handle_proxy
函数的处理上,特别是这一行:let cache = cache.read().unwrap();
。这个错误表明在get(handle_proxy)
中,Rust 编译器无法确定handle_proxy
函数是否实现了axum::handler::Handler
trait。
要解决此问题,您可以尝试为handle_proxy
函数显式指定其返回类型,以确保它满足axum::handler::Handler
trait 的要求。例如:
async fn handle_proxy(
cache: Extension<Cache>,
req: Request<Body>,
) -> Response<Body> {
let cache = cache.read().unwrap();
// ...
}
这将明确告诉编译器handle_proxy
函数的返回类型,以符合Axum的要求。希望这有助于解决问题。如果您需要更多帮助,请告诉我。
英文:
Recently, I've started to learn Rust to build some simple web apps with Axum. However, I ended having an unexplained error while building the app, and I could not find the reason of it.
The failing to be built application code is the following:
use axum::{
body::{Body, boxed, StreamBody},
Extension,
http::Request,
response::Response,
Router,
routing::get,
};
use std::{
path::PathBuf,
sync::{Arc, RwLock},
};
type Cache = Arc<RwLock<PathBuf>>;
async fn handle_proxy(
cache: Extension<Cache>,
req: Request<Body>,
) -> Response {
let cache = cache.read().unwrap();
if let Some(object_key) = req.uri().path().rsplitn(2, '/').next() {
// later the cache variable will be used to build the given path
let file = tokio::fs::File::open("/tmp/testaroo").await;
let buf_reader = tokio::io::BufReader::new(file.unwrap());
let stream = tokio_util::io::ReaderStream::new(buf_reader);
return Response::builder().body(boxed(StreamBody::new(stream))).unwrap();
}
// The function is not fully built here, there will be more code later, useless to demo the error.
Response::builder().body(boxed("".to_string())).unwrap()
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/:key", get(handle_proxy));
let addr = "0.0.0.0:8080";
axum::Server::bind(&addr.parse().unwrap()).serve(app.into_make_service()).await.unwrap();
}
When the let cache = cache.read().unwrap();
line is present (not commented above), the program is no longer building with the following error:
> cargo clippy
Checking hello-rs-axum-failure v0.1.0 (/home/mycroft/tmp/broken-thing)
error[E0277]: the trait bound `fn(axum::Extension<std::sync::Arc<std::sync::RwLock<std::path::PathBuf>>>, axum::http::Request<axum::body::Body>) -> impl std::future::Future<Output = axum::http::Response<http_body::combinators::box_body::UnsyncBoxBody<axum::body::Bytes, axum::Error>>> {handle_proxy}: axum::handler::Handler<_, _, _>` is not satisfied
--> src/main.rs:34:48
|
34 | let app = Router::new().route("/:key", get(handle_proxy));
| --- ^^^^^^^^^^^^ the trait `axum::handler::Handler<_, _, _>` is not implemented for fn item `fn(axum::Extension<std::sync::Arc<std::sync::RwLock<std::path::PathBuf>>>, axum::http::Request<axum::body::Body>) -> impl std::future::Future<Output = axum::http::Response<http_body::combinators::box_body::UnsyncBoxBody<axum::body::Bytes, axum::Error>>> {handle_proxy}`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `axum::handler::Handler<T, S, B>`:
<axum::handler::Layered<L, H, T, S, B, B2> as axum::handler::Handler<T, S, B2>>
<axum::routing::MethodRouter<S, B> as axum::handler::Handler<(), S, B>>
note: required by a bound in `axum::routing::get`
--> /home/mycroft/.cargo/registry/src/github.com-1ecc6299db9ec823/axum-0.6.18/src/routing/method_routing.rs:403:1
|
403 | top_level_handler_fn!(get, GET);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `get`
= note: this error originates in the macro `top_level_handler_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
error: could not compile `hello-rs-axum-failure` due to previous error
I understand that adding the line is breaking something, but why? I found out limiting the scope of the declaration (ie: putting the instruction in its own scope and copying the underlying variable) will help, but I'd really like to know why the error is happening.
答案1
得分: 1
在异步处理函数中的代码部分保留了cache
值的guard
。
正如您发现的那样,这个guard
不是Send
,因此不能跨越await
,因为执行可能在从await
中恢复执行后继续在不同线程上进行。
解决这个问题有两种可能性:
-
更改代码,以便在
await
边界上不保持guard
。(可能可行,也可能不可行或不可取。) -
使用类似于tokio::sync::RwLock的异步并发结构,而不是标准库中的结构。这些结构可以跨越
await
边界持有。
英文:
The code in the async handler function is holding onto the guard for the cache
value in the scope.
As you discovered, this guard is not Send
, so it can't be held across await
s because the execution might continue on a different thread after resuming execution from an await
.
Two possibilities to solve this:
-
Change the code so you don't hold the guard across an
await
boundary. (May or may not be possible or desirable.) -
Use an async concurrency structure like tokio::sync::RwLock instead of the one in the standard library. These can be held across
await
boundaries.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论