Временная стоимость упала во время заимствования, но я не хочу сдавать в аренду

Я делаю примерно так:

fn main() {
    //[1, 0, 0, 0, 99]; // return [2, 0, 0, 0, 99]
    //[2, 3, 0, 3, 99]; // return [2,3,0,6,99]
    //[2, 4, 4, 5, 99, 0]; // return [2,4,4,5,99,9801]
    //[1, 1, 1, 4, 99, 5, 6, 0, 99]; // return [30,1,1,4,2,5,6,0,99]

    let map: Vec<(&mut [usize], &[usize])> = vec![(&mut [1, 0, 0, 0, 99], &[2, 0, 0, 0, 99])];

    for (x, y) in map {
        execute_program(x);
        assert_eq!(x, y);
    }
}

pub fn execute_program(vec: &mut [usize]) {
    //do something inside vec
}

Здесь игровая площадка

Проблема в том, что я не использую let для первого элемента в кортеже, который я хочу позаимствовать для execute_program:

error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:2:57
  |
2 |     let map: Vec<(&mut [usize], &[usize])> = vec![(&mut [1, 0, 0, 0, 99], &[2, 0, 0, 0, 99])];
  |                                                         ^^^^^^^^^^^^^^^^                     - temporary value is freed at the end of this statement
  |                                                         |
  |                                                         creates a temporary which is freed while still in use
3 | 
4 |     for (x, y) in map {
  |                   --- borrow later used here
  |
  = note: consider using a `let` binding to create a longer lived value

Но то, что я делал, было рефакторингом именно потому, что я не хотел делать let для каждого среза, который хочу протестировать!

let действительно нужен?


person Cirelli94    schedule 05.12.2019    source источник
comment
Почему вы занимаетесь там, а не позже? play.rust-lang.org/   -  person loganfsmyth    schedule 05.12.2019


Ответы (1)


Что ж, какой-то объект должен владеть каждым из этих массивов, потому что ссылки не могут владеть объектами. И массивы бывают разных размеров, поэтому владельцем должен быть указатель. Самый распространенный указатель-владелец, подобный массиву, - Vec:

let map: Vec<(Vec<usize>, &[usize])> = vec![
    (vec![1, 0, 0, 0, 99], &[2, 0, 0, 0, 99]),
    (vec![2, 3, 0, 3, 99], &[2, 3, 0, 6, 99]),
    (vec![2, 4, 4, 5, 99, 0], &[2, 4, 4, 5, 99, 9801]),
    (vec![1, 1, 1, 4, 99, 5, 6, 0, 99], &[30, 1, 1, 4, 2, 5, 6, 0, 99]),
];

for (mut x, y) in map {
    execute_program(&mut x);
    assert_eq!(x, y);
}

Таким образом, массивы принадлежат map и заимствуются при необходимости, что также предлагает loganfsmyth в комментариях к вопросу.

Возможно, вас беспокоит снижение производительности из-за ненужных выделений. Это стоимость использования одного let; поскольку все массивы имеют разный размер, если вы хотите, чтобы они были в стеке, на самом деле нет способа объявить их с разными lets. Однако вы можете написать макрос, удаляющий шаблон.

Подождите, а почему это работает для y?

Вы можете спросить, почему я превратил x в вектор, а y оставил как есть. Ответ заключается в том, что, поскольку y является общей ссылкой, эти массивы подчиняются статическое продвижение, так что &[2, 0, 0, 0, 99] фактически относится к типу &'static [usize; 5], который может быть приведен к &'static [usize]. &mut ссылки не запускают статическое продвижение, потому что изменять статическое значение без какой-либо синхронизации небезопасно.

person trentcl    schedule 05.12.2019