* mut (dyn std :: ops :: Fn () + 'stati c) `нельзя безопасно разделить между потоками с помощью структуры serde :: de :: DeserializeOwned - PullRequest
1 голос
/ 08 марта 2020

Я пытаюсь использовать Iced (каркас пользовательского интерфейса, основанный на архитектуре Elm) с Reqwest (оболочка над гипер) , который может использовать Serde для JSON десериализации .

Независимо от того, что они работают правильно, но я новичок в Rust, и что-то в моей реализации неверно.

Я начинаю с (в процессе) сетевой функции.

#[derive(Deserialize, Debug, Clone)]
pub(crate) enum Error {
    APIError,
    ParseError,
}

impl From<reqwest::Error> for Error {
    fn from(error: reqwest::Error) -> Self {
        Error::APIError
    }
}

pub(crate) async fn post<T>(request: Request) -> Result<T, Error>
where
    T: DeserializeOwned + Debug + Clone,
{
    let headers = standard_headers(request.params);
    let response = Client::new()
        .post(&format!("{}{}", request.base, request.path))
        .json(&request.body)
        .headers(headers)
        .send()
        .await?
        .json::<T>()
        .await?;

    Ok(response)
}

и я пытаюсь использовать его как часть Iced:

fn new() -> (Runner, Command<Message>) {
    (
        Runner::Loading,
        Command::perform(post(Login::request()), Message::Next),
    )
}

и получаю ошибку компиляции:

error[E0277]: `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
  --> src/feature/runner/runner.rs:42:13
   |
42 |             Command::perform(post(Login::request()), Message::Next),
   |             ^^^^^^^^^^^^^^^^ `*mut (dyn std::ops::Fn() + 'static)` cannot be shared between threads safely
   | 
  ::: <snip>/futures/src/command/native.rs:29:22
   |
29 |         future: impl Future<Output = T> + 'static + Send,
   |                      ------------------ required by this bound in `iced_futures::command::native::Command::<T>::perform`
   |
   = help: within `core::fmt::Void`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`

Я считаю, что проблема связана с используя T: DeserializeOwned и время жизни в post, причем владение таково, что тип T в async fn post может быть в другом потоке по сравнению с асинхронным вызовом c в Command (отсюда и упоминание о Send.

. Ответ может быть даже в пожизненной ссылке, но у меня пока недостаточно знаний, чтобы увидеть его или узнать, нахожусь ли я в нужном месте с моими Я вернулся к использованию только конкретного типа вместо T whi ch работает.

Мне бы очень хотелось понять, почему существует эта проблема и что я могу сделать, чтобы ее решить.

Заранее спасибо!

1 Ответ

0 голосов
/ 07 мая 2020

Этот намек:

help: within `core::fmt::Void`, the trait `std::marker::Sync` is not implemented for `*mut (dyn std::ops::Fn() + 'static)`

заставляет меня думать, что вся эта проблема связана с вашим использованием format! в fn post (см. https://github.com/rust-lang/rust/issues/64960). Попробуйте обновить компилятор ржавчины или переместить URL-адрес перед длинной цепочкой .await:

let url = format!("{}{}", request.base, request.path);
let response = Client::new()
    .post(&url)
    // ...
...