Rust: объединение и повторение результатов фьючерсов - PullRequest
0 голосов
/ 02 августа 2020

У меня есть код, который выполняет итерацию по объектам и использует метод asyn c для каждого из них последовательно, прежде чем что-то делать с результатами. Я хотел бы изменить его так, чтобы вызовы метода asyn c объединялись в одно будущее перед выполнением. Важный бит ниже находится в HolderStruct::add_squares. Мой текущий код выглядит так:

use anyhow::Result;

struct AsyncMethodStruct {
    value: u64
}

impl AsyncMethodStruct {
    fn new(value: u64) -> Self {
        AsyncMethodStruct {
            value
        }
    }
    async fn get_square(&self) -> Result<u64> {
        Ok(self.value * self.value)
    }
}

struct HolderStruct {
    async_structs: Vec<AsyncMethodStruct>
}

impl HolderStruct {
    fn new(async_structs: Vec<AsyncMethodStruct>) -> Self {
        HolderStruct {
            async_structs
        }
    }
    async fn add_squares(&self) -> Result<u64> {
        let mut squares = Vec::with_capacity(self.async_structs.len());
        for async_struct in self.async_structs.iter() {
            squares.push(async_struct.get_square().await?);
        }
        let mut sum = 0;
        for square in squares.iter() {
            sum += square;
        }

        return Ok(sum);
    }
}

Я бы хотел изменить HolderStruct::add_squares на что-то вроде этого:

use futures::future::join_all;
// [...]
impl HolderStruct {
    async fn add_squares(&self) -> Result<u64> {
        let mut square_futures = Vec::with_capacity(self.async_structs.len());
        for async_struct in self.async_structs.iter() {
            square_futures.push(async_struct.get_square());
        }
        let square_results = join_all(square_futures).await;
        let mut sum = 0;
        for square_result in square_results.iter() {
            sum += square_result?;
        }

        return Ok(sum);
    }
}

Однако компилятор выдает мне эту ошибку, используя приведенное выше :

error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try`
  --> src/main.rs:46:20
   |
46 |             sum += square_result?;
   |                    ^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `&std::result::Result<u64, anyhow::Error>`
   |
   = help: the trait `std::ops::Try` is not implemented for `&std::result::Result<u64, anyhow::Error>`
   = note: required by `std::ops::Try::into_result`

Как мне изменить код, чтобы не было этой ошибки?

1 Ответ

1 голос
/ 02 августа 2020
for square_result in square_results.iter()

Здесь потеряйте вызов iter().

for square_result in square_results

Кажется, у вас сложилось впечатление, что вызов iter() является обязательным для итерации по коллекции. Фактически, все, что реализует IntoIterator , можно использовать в for l oop.

Вызов iter () на Vec<T> derefs для slice (&[T]) и дает итератор по ссылкам на элементы вектора. Оператор ? пытается извлечь значение из Result, но это возможно только в том случае, если вы владеете Result, а не просто имеете ссылку на него.

Однако, если вы просто используете вектор в операторе for, он будет использовать реализацию IntoIterator для Vec<T>, что даст элементы типа T, а не &T.

square_results.into_iter() выполняет то же самое, но более многословно. В основном это полезно при использовании итераторов в функциональном стиле, например vector.into_iter().map(|x| x + 1).collect().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...