我有一些看起来像这样的代码。
async move {
let res = do_sth(&state).await;
(state, res)
}.boxed()
(完整的例子: https:/gitlab.commsrd0async-issue)
我想说的是 async move
块的所有权。state
并传递一个 state
伴随 do_sth
方法,它是一个 async fn
. 然而,编译器也保留了 &state
跨越 await
绑定,我不知道它为什么会这样做。
error: future cannot be sent between threads safely
--> src/main.rs:30:5
|
30 | }.boxed()
| ^^^^^ future returned by `read_all` is not `Send`
|
= help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)`
note: future is not `Send` as this value is used across an await
--> src/main.rs:28:14
|
28 | let res = do_sth(&state).await;
| ^^^^^^^------^^^^^^^- `&state` is later dropped here
| | |
| | has type `&gotham::state::State`
| await occurs here, with `&state` maybe used later
我试着把 do_sth
呼叫 await
到它自己的块中,但这并没有解决这个错误。
有什么办法可以避免这个错误吗?
这个错误很明显与所有权或寿命无关。
error: future cannot be sent between threads safely
gotham_restful::State
没有实现 Sync
特质,这意味着它的参照物 &state
是不线程安全的。但是,你将该引用传递给异步函数,然后该函数被等待,Rust编译器会自动推断该函数不是线程安全的,所以整个块变得 "不是线程安全"。Rust编译器的 read_all
方法有 + Send
约束,但是,要求返回的future是线程安全的,所以这会导致错误。
一个可能的解决方案是重写 do_sth
成为一个返回未来的常规函数。这样你就可以确保从该函数返回的future实现了 Send
是线程安全的,而不是依靠编译器来推断它的线程安全与否。
fn do_sth(_state: &State) -> impl Future<Output = NoContent> + Send {
// require that the future of this function is thread-safe ---^
async move {
Default::default()
}
}
请注意,这实际上并不允许你做任何非线程安全的事情,但是它将指示编译器说 do_sth
函数应该是线程安全的,而不是试图手动推断它是否应该是安全的。