Как я могу выполнить итерацию запроса Bevy и сохранить ссылку на повторяемое значение, чтобы я мог использовать его позже?

У меня есть взаймы в emptyпеременная и хочу продлить ей жизнь. В закомментированном блоке кода я пытаюсь обратиться к нему, но ссылка больше не доступна. Мне нужно снова пройти цикл, чтобы найти совпадение, чтобы действовать в соответствии с ним.

Как я могу выполнить запрос в поисках наилучшего соответствия, а затем действовать в соответствии с ним, как только я узнаю, что это наилучшее совпадение, без необходимости повторять цикл, чтобы найти его снова?

use bevy::prelude::*;

struct Person;
struct Name(String);

fn main() {
    App::build()
        .add_default_plugins()
        .add_startup_system(startup.system())
        .add_system(boot.system())
        .run();
}

fn boot(mut query: Query<(&Person, &mut Name)>) {
    let mut temp_str = String::new();
    let mut empty: Option<&mut Name> = None;
    for (_p, mut n_val) in &mut query.iter() {
        if n_val.0.to_lowercase() > temp_str.to_lowercase() {
            temp_str = n_val.0.clone();
            empty = Some(&mut n_val);
        }
    }
    println!("{}", temp_str);
    if let Some(n) = empty {
        // ...
    }
    // for (_p, mut n_val) in &mut query.iter() {
    //     if n_val.0 == temp_str {
    //         n_val.0 = "a".to_string();
    //     }
    // }
}

fn startup(mut commands: Commands) {
    commands
        .spawn((Person, Name("Gene".to_string())))
        .spawn((Person, Name("Candace".to_string())))
        .spawn((Person, Name("Zany".to_string())))
        .spawn((Person, Name("Sarah".to_string())))
        .spawn((Person, Name("Carl".to_string())))
        .spawn((Person, Name("Robert".to_string())));
}

Cargo.toml:

[package]
name = "sample"
version = "0.1.0"
authors = [""]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bevy = "0.1.3"

Конкретная ошибка:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:17:33
   |
17 |     for (_p, mut n_val) in &mut query.iter() {
   |                                 ^^^^^^^^^^^-
   |                                 |          |
   |                                 |          temporary value is freed at the end of this statement
   |                                 creates a temporary which is freed while still in use
...
24 |     if let Some(n) = empty {
   |                      ----- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

error[E0597]: `n_val` does not live long enough
  --> src/main.rs:20:26
   |
20 |             empty = Some(&mut n_val);
   |                          ^^^^^^^^^^ borrowed value does not live long enough
21 |         }
22 |     }
   |     - `n_val` dropped here while still borrowed
23 |     println!("{}", temp_str);
24 |     if let Some(n) = empty {
   |                      ----- borrow later used here

1 ответ

Решение

Вы не можете продлить срок жизни ссылки, но это не ваша проблема, ошибка говоритtemporary value dropped while borrowed, поэтому вы должны продлить срок службы временного файла.

Если вам интересно, что временное, компилятор также указывает на это (буквально) в сообщении об ошибке: query.iter(). Это вызов функции, а возвращаемое значение ни с чем не связано, поэтому компилятор создает для него временное значение. Затем вы повторяете, используя ссылку на этот временный объект. Когдаfor цикл заканчивается, временный объект удаляется, и срок его существования истекает.

Решение - привязать временную переменную к локальной. Таким образом вы продлите время жизни объекта до области видимости переменной:

let mut iter = query.iter();
for (_p, n_val) in &mut iter {
    if n_val.0.to_lowercase() > temp_str.to_lowercase() {
        temp_str = n_val.0.clone();
        empty = Some(n_val);
    }
}

PS: я считаю довольно странной схему повторения &mut iter. Я ожидал возвращенияiter() реализовать Iterator или IntoIteratorпрямо, но похоже, что это не так.

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