Ссылка сохраняется вне зависимости от того, используется ли область действия, если она принадлежит - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть код, который выглядит следующим образом:

async move {
    let res = do_sth(&state).await;
    (state, res)
}.boxed()

(Полный пример: https://gitlab.com/msrd0/async-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 в свой собственный блок, но это не исправило ошибку.

Есть ли способ избежать этой ошибки?

1 Ответ

2 голосов
/ 18 апреля 2020

Ошибка довольно явно не связана с владельцем или временем жизни:

error: future cannot be sent between threads safely

gotham_restful::State не реализует черту Sync, что означает, что ее ссылка &state не является потокобезопасным. Однако вы передаете эту ссылку асинхронной функции, которая затем ожидается, и компилятор Rust автоматически делает вывод, что эта функция не является поточно-ориентированной, поэтому весь блок становится «не поточно-безопасным». Возвращаемое значение метода read_all имеет ограничение + <a href="https://doc.rust-lang.org/stable/std/marker/trait.Send.html" rel="nofollow noreferrer">Send</a>, однако требует, чтобы возвращаемое будущее было потокобезопасным, поэтому это вызывает ошибку.


Одним из возможных решений является перезапись do_sth быть обычной функцией, которая возвращает будущее. Таким образом, вы можете убедиться, что возвращаемое будущее от этой функции реализует 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 должна быть поточно-безопасной, вместо того, чтобы пытаться вручную сделать вывод, должно ли это быть или нет.

...