Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

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

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...