Temporary value dropped while borrowed, but I don't want to do a let

橙三吉。 提交于 2020-12-21 02:42:13

问题


I'm doing something like this:

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
}

Here the playground

The problem is that I don't use the let on the first element in the tuple, that i want to borrow to 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

But what I was doing was a refactoring exactly because I didn't want to do a let for every slice I want to test!

Is the let really needed?


回答1:


Well, something has to own each of those arrays, because references can't own things. And the arrays are of different sizes, so the owner has to be a pointer. The most common array-like owning pointer is 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);
}

The arrays are therefore owned by map and borrowed when necessary, as loganfsmyth also suggested in the question comments.

You may be concerned about the performance cost of making unnecessary allocations. This is the cost of using a single let; since the arrays are not all the same size, if you want them on the stack there really isn't a way around declaring them with different lets. However, you could write a macro that removes the boilerplate.

Wait, why does it work for y?

You may wonder why I turned x into a vector, but left y as it is. The answer is that because y is a shared reference, those arrays are subject to static promotion, so that &[2, 0, 0, 0, 99] is actually of type &'static [usize; 5] which can be coerced to &'static [usize]. &mut references do not trigger static promotion because it is unsafe to mutate a static value without some kind of synchronization.



来源:https://stackoverflow.com/questions/59193616/temporary-value-dropped-while-borrowed-but-i-dont-want-to-do-a-let

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!