问题
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 let
s. 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