Rust: невозможно вернуть значение, ссылающееся на временное значение

Noob в ржавчине здесь, пытается реализовать общую функцию повтора и пытается решить, как устранить ошибку времени жизни:

async fn retry<T, E, Fut, F>(mut f: F, client: &Client, max_retries: i32) -> Result<T, E>
    where
        Fut: Future<Output = Result<T, E>>,
        F: FnMut(&Client) -> Fut,
{
    let mut count = 0;
    loop {
        let result = f(client).await;

        if result.is_ok() {
            break result;
        } else {
            if count > max_retries {
                break result;
            }
            count += 1;
        }
    }
}

и ошибка

| |_________________^ returning this value requires that `'1` must outlive `'2`

error[E0515]: cannot return value referencing temporary value

Как я вызываю метод:

let lambda = &mut move |client: &Client| {
            client
                .download_object(
                    &GetObjectRequest {
                        bucket: some_bucket,
                        object: some_object,
                        ..Default::default()
                    },
                    &Range::default(),
                )
        };
        retry(lambda, &self.client, 5).await

Я не могу понять, что возвращаемое значение f(client).await должно пережить что именно?

Полная ошибка:

error[E0621]: explicit lifetime required in the type of `client`
  --> src/main.rs:35:22
   |
28 | async fn retry<'a, T, E, Fut, F>(mut f: F, client: &Client, max_retries: i32) -> Result<T, E>
   |                                                    ------- help: add explicit lifetime `'a` to the type of `client`: `&'a Client`
...
35 |         let result = f(client).await;
   |                      ^^^^^^^^^ lifetime `'a` required

error: lifetime may not live long enough
  --> src/main.rs:68:13
   |
67 |           let lambda = &mut move |client: &Client| {
   |                                           -      - return type of closure `impl Future<Output = Result<Vec<u8>, google_cloud_storage::http::Error>>` contains a lifetime `'2`
   |                                           |
   |                                           let's call the lifetime of this reference `'1`
68 | /             client
69 | |                 .download_object(
70 | |                     &GetObjectRequest {
71 | |                         bucket: some_bucket,
...  |
75 | |                     &Range::default(),
76 | |                 )
   | |_________________^ returning this value requires that `'1` must outlive `'2`

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:68:13
   |
68 | /              client
69 | |                  .download_object(
70 | |                      &GetObjectRequest {
   | | ______________________-
71 | ||                         bucket: some_bucket,
72 | ||                         object: some_object,
73 | ||                         ..Default::default()
74 | ||                     },
   | ||_____________________- temporary value created here
75 | |                      &Range::default(),
76 | |                  )
   | |__________________^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing temporary value
  --> src/main.rs:68:13
   |
68 | /             client
69 | |                 .download_object(
70 | |                     &GetObjectRequest {
71 | |                         bucket: some_bucket,
...  |
75 | |                     &Range::default(),
   | |                      ---------------- temporary value created here
76 | |                 )
   | |_________________^ returns a value referencing data owned by the current function

Что такое Client?

Chayim Friedman 20.04.2023 14:48

Где остальные ошибки? Пожалуйста, всегда публикуйте полное сообщение об ошибке с помощью cargo build

cafce25 20.04.2023 14:51

@cafce25 добавил полную ошибку в описание

akram 20.04.2023 15:19
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
3
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не знаю, что такое Client, поэтому я могу только догадываться, но мое обоснованное предположение состоит в том, что будущее download_object() возвращает заимствование у клиента, но ваша сигнатура функции retry() не позволяет этого.

Поскольку вы передаете Client функции, самый простой способ — аннотировать время жизни:

async fn retry<'a, T, E, Fut, F>(mut f: F, client: &'a Client, max_retries: i32) -> Result<T, E>
where
    Fut: Future<Output = Result<T, E>>,
    F: FnMut(&'a Client) -> Fut,
{
    // ...
}

Если бы client генерировался внутри функции, это было бы сложнее. См. Вызов универсальной асинхронной функции с (изменяемым) заимствованным аргументом.

спасибо, попробовал аннотировать на всю жизнь, и проблема не устранена. Клиент - это клиент из этого crate - docs.rs/google-cloud-storage/latest/google_cloud_storage/cli‌​ent/…

akram 20.04.2023 15:10

@akram Судя по ошибке в вопросе, вы не использовали &'a Client.

Chayim Friedman 20.04.2023 19:30

правильно, поэтому &'a Client решит одну пожизненную проблему, а их на одну больше, чем осталось: ``` &GetObjectRequest { | | ______________________- 71 | || ведро: some_bucket, 72 | || объект: некоторый_объект, 73 | || ..Default::default() 74 | || }, | ||_____________________- здесь создано временное значение ``` ошибка [E0515]: невозможно вернуть значение, ссылающееся на временное значение

akram 20.04.2023 20:29

мое понимание второй проблемы cannot return value referencing temporary value таково, что если бы методы не были асинхронными, то второй ошибки не произошло бы, потому что она возвращает Future, возможно, что временные значения могут выйти из области действия до завершения Future, что приведет к оборванной ссылке и undefined поведение? любые подсказки, как решить второй тоже.

akram 20.04.2023 20:35

@akram Теперь это другой вопрос, и я также думаю, что у него нет решения.

Chayim Friedman 20.04.2023 20:43

спасибо за его ясный, более глупый вопрос, связанный с этим, если метод повторной попытки не принимал клиента в качестве аргумента, а только closure / mut f: FnMut() -> Fut, как в этом случае будет решена проблема с продолжительностью жизни?

akram 20.04.2023 21:05

@akram На это есть ответ в вопросе, который я связал.

Chayim Friedman 20.04.2023 21:09

Я думаю, что это для сценария, когда клиент генерируется внутри функции, я имел в виду сценарий, когда клиент не генерируется внутри функции, вот пример, иллюстрирующий то же самое - play.rust-lang.org/…

akram 20.04.2023 21:15

@akram Ну, если он не создается внутри функции и не передается ей, то где он создается?

Chayim Friedman 20.04.2023 21:19

он создается вызываемым пользователем прямо перед созданием замыкания. пусть клиент = Клиент: новый(); пусть лямбда = двигаться || { client.download_object(&request, &range)};

akram 20.04.2023 21:28

@akram Я не верю, что это решаемо. Вам придется использовать пользовательский трейт, а не замыкание.

Chayim Friedman 20.04.2023 21:35

Другие вопросы по теме