Rust error[E0716]: temporary value dropped while borrowed - rust

I had been to this question earlier because the question and the answer(s) were very useful. Yet, my case seems to be somewhat different. Hence, this post:
Because this example (and the accompanying solution/explanation) are very similar to my case, I thought of adding it here (instead of asking a new question).
I am simply trying to read the entries of a directory (Ubuntu Linux 22.10, ext4 filesystem):
let mut all_chosenfiles: Vec<&str> = Vec::new();
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
let chosen_file = next_file.unwrap().path();
all_chosenfiles.push(chosen_file.to_owned().to_str().unwrap());
}
}
}
}
Not very idiomatic, I agree, but it serves the purpose at hand.
The compiler is not happy though:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:31:46
|
31 | all_chosenfiles.push(chosen_file.to_owned().to_str().unwrap());
| ---------------------^^^^^^^^^^^^^^^^^^^^^^-------------------- temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I understand what is she complaining about. I have tried to pacify her, by using let as has been prescribed here:
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
let chosen_path = next_file.unwrap().path();
let chosen_file = &chosen_path.to_owned().to_str().unwrap();
all_chosenfiles.push(chosen_file);
}
}
}
}
She is stubborn:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:31:44
|
31 | let chosen_file = &chosen_path.to_owned().to_str().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
32 | all_chosenfiles.push(chosen_file);
| ----------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
I am scratching my head. I am missing some idiom, I am sure.
Is a derefencing using '*' operator (viz., *chosent_file) the only way out?

I have gotten around, for the time being, by:
let mut all_chosenfiles: Vec<String> = Vec::new(); // of String, and not of &str
for next_path in path_components {
for next_dir_entry in fs::read_dir(next_path) {
for next_file in next_dir_entry {
let file_metadata = next_file.as_ref().unwrap().metadata().unwrap();
if file_metadata.is_file()
&& file_metadata.mode() & 0o500 == 0o500 {
// Using as_ref() before unwrapping
let chosen_path: PathBuf = next_file.as_ref().unwrap().path();
// Doc says that, to_str()
// "Yields a &str slice if the Path is valid unicode"
let chosen_file: Option<&str> = chosen_path.to_str();
// Explicitly owning a String, made out of &str, below!
all_chosenfiles.push(chosen_file.unwrap().to_owned());
}
}
}
}
Honestly, I am not really sure why it is working. By calling next_file.as_ref(), I ensure that a reference to that memory is held. But, how does that solve the problem of temporary which is freed etc. issue? Moreover, cloning the pathstrings by using to_str() seems to be wasteful to me.
Help me fill in, the gaps in my understanding!

Related

How to use FileReader in rust wasm?

This is part of my code, the error in rest move |event: Event|
pub struct FileStream{
el : HtmlInputElement,
}
impl FileStream {
pub fn new(el : HtmlInputElement) -> FileStream {
FileStream {el}
}
pub fn get_file(&self){
let file = self.el.files().unwrap().get(0).unwrap();
let file_reader = FileReader::new().unwrap();
file_reader.read_as_data_url(&file).unwrap();
let onloadend = Closure::wrap(Box::new(move |event: Event| {
let file_reader = file_reader.unchecked_into::<web_sys::FileReader>();
let data_url = file_reader.result().unwrap();
let data_url = data_url.unchecked_into::<JsValue>();
let data_url = data_url.as_string().unwrap();
let audio_el = self.el.unchecked_into::<HtmlAudioElement>();
audio_el.set_src(&data_url);
}) as Box<dyn FnMut(_)>);
file_reader.set_onloadend(Some(onloadend.as_ref().unchecked_ref()));
}
}
I don't know how to fix this error...
error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
--> src/lib.rs:29:48
|
29 | let onloadend = Closure::wrap(Box::new(move |event: Event| {
| - ^^^^^^^^^^^^^^^^^^^ this closure implements `FnOnce`, not `FnMut`
| _______________________________________|
| |
30 | | let file_reader = file_reader.unchecked_into::<web_sys::FileReader>();
| | ----------- closure is `FnOnce` because it moves the variable `file_reader` out of its environment
31 | | let data_url = file_reader.result().unwrap();
32 | | let data_url = data_url.unchecked_into::<JsValue>();
... |
35 | | audio_el.set_src(&data_url);
36 | | }) as Box<dyn FnMut(_)>);
| |__________- the requirement to implement `FnMut` derives from here
For more information about this error, try `rustc --explain E0525`.
When the closure is created, it moves file_reader into itself (because it is declared as a move || closure). Then, when the closure is called, it consumes file_reader via calling unchecked_into(). Therefore, if the closure were to be called a second time, it would no longer have a file_reader to use. That's why the compiler decides the closure is only a “FnOnce”.
On the other hand, the set_onloadend callback mechanism wants a function that can be called more than once, in case the underlying event somehow happens more than once.
The general solution to this problem is to adjust your function so that it can be called more than once — as far as the compiler is concerned. You can do this by putting the value that must be moved in an Option outside the closure, then using Option::take() inside the closure to get it back out — thus leaving the Option value to be None if the function ever gets called again.
However, in this case, it would be simpler to just remove the entire unchecked_into() line. As far as I can see, there is no need for it, because the object is already typed as a FileReader. (But I haven't tried compiling your code to see if it works without, so maybe I missed something.)

Rust: argument requires that `[VARIABLE]` is borrowed for `'static` [duplicate]

This question already has answers here:
Spawn non-static future with Tokio
(2 answers)
Can you specify a non-static lifetime for threads? [duplicate]
(1 answer)
How do I use static lifetimes with threads?
(2 answers)
How can I send non-static data to a thread in Rust and is it needed in this example?
(1 answer)
Closed 10 months ago.
This post was edited and submitted for review 10 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I get this unhelpful error message:
error[E0597]: `msg` does not live long enough
--> src/main.rs:25:23
|
25 | let msg_str = msg.as_str();
| ^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `msg` is borrowed for `'static`
...
51 | }
| - `msg` dropped here while still borrowed
From the following Rust code:
for msg in rx {
let msg_str = msg.as_str();
let msg_type = get_msg_type(exchange, &msg_str);
println!("{}", &msg_str);
let join_handle = spawn_blocking(move || { parse_trade(exchange, market_type, &msg_str) });
match join_handle.await {
Ok(trade) => {
let t = &trade.unwrap()[0];
},
Err(error) => panic!("Problem joining: {:?}", error),
}
}
But it doesn't tell me how to do a static borrow of msg in this case.
What is a viable solution here?
None of the following proposed duplicate questions are equivalent to this question:
Spawn non-static future with Tokio
Can you specify a non-static lifetime for threads?
How do I use static lifetimes with threads?
How can I send non-static data to a thread in Rust and is it needed in this example?
The problem is that msg is a variable you get from the iteration, and therefore is only valid during one iteration step. It ceases to exist at the end of the iteration step, hence the comiler message - msg dropped here while still borrowed at the end of the loop.
The reason why this is a problem is because you move the reference msg_str into the closure via move ||, and the rust compiler cannot infer that spawn_blocking drops it before the end of the loop. (it can't infer it because it would be incorrect; join_handle.await could get cancelled, which would NOT cancel the spawned task and would cause &msg_str to be a dangling reference)
But it doesn't tell me how to do a static borrow of msg in this case.
You can't borrow statically from a temporal variable. That is the definition of a 'static borrow, that it does not cease to exist after a while.
Sadly without knowing the types of the variables / function parameters I can't give you any advice how you could solve this. You probably want to introduce a clone somewhere, but hard to tell where exactly without knowing types.
Guess of a solution
I tried to infer a minimal reproducible example from your question.
I assume that the types are as followed:
use tokio::task::spawn_blocking;
fn parse_trade(_msg: &str) -> Result<Vec<u32>, String> {
Ok(vec![1, 2, 3])
}
#[tokio::main]
async fn main() {
let rx = vec!["a".to_string(), "b".to_string()];
for msg in rx {
let msg_str = msg.as_str();
println!("{}", &msg_str);
let join_handle = spawn_blocking(move || parse_trade(&msg_str));
match join_handle.await {
Ok(trade) => {
let t = &trade.unwrap()[0];
}
Err(error) => panic!("Problem joining: {:?}", error),
}
}
}
Which does show the following error message:
error[E0597]: `msg` does not live long enough
--> src/main.rs:12:23
|
12 | let msg_str = msg.as_str();
| ^^^^^^^^^^^^
| |
| borrowed value does not live long enough
| argument requires that `msg` is borrowed for `'static`
...
23 | }
| - `msg` dropped here while still borrowed
This is a possible solution:
use tokio::task::spawn_blocking;
fn parse_trade(_msg: &str) -> Result<Vec<u32>, String> {
Ok(vec![1, 2, 3])
}
#[tokio::main]
async fn main() {
let rx = vec!["a".to_string(), "b".to_string()];
for msg in rx {
let msg_str = msg.as_str();
let msg_clone = msg.clone();
println!("{}", &msg_str);
let join_handle = spawn_blocking(move || parse_trade(msg_clone.as_str()));
match join_handle.await {
Ok(trade) => {
let t = &trade.unwrap()[0];
}
Err(error) => panic!("Problem joining: {:?}", error),
}
}
}
You create a .clone() of msg and move this one into the closure instead. It carries ownership of the cloned string into the closure, and it therefore does no longer depend on the msg variable.

How can I conditionally provide a default reference without performing unnecessary computation when it isn't used?

I have some variable passed into my function by reference. I don't need to mutate it or transfer ownership, I just look at its contents. If the contents are in some state, I want to replace the value with a default value.
For instance, my function accepts a &Vec<String> and if the Vec is empty, replace it with vec!["empty"]:
fn accept(mut vec: &Vec<String>) {
if vec.len() == 0 {
vec = &vec!["empty".to_string()];
}
// ... do something with `vec`, like looping over it
}
But this gives the error:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:3:16
|
1 | fn accept(mut vec: &Vec<String>) {
| - let's call the lifetime of this reference `'1`
2 | if vec.len() == 0 {
3 | vec = &vec!["empty".to_string()];
| -------^^^^^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| assignment requires that borrow lasts for `'1````
Preventing the mut results in the same error as the previous example:
fn accept(input: &Vec<String>) {
let vec = if input.len() == 0 {
&vec!["empty".to_string()]
} else {
input
};
// ... do something with `vec`, like looping over it
}
The only solution I've come up with is to extract the default value outside the if and reference the value:
fn accept(input: &Vec<String>) {
let default = vec!["empty".to_string()];
let vec = if input.len() == 0 {
&default
} else {
input
};
// ... do something with `vec`
}
This results in less clean code and also unnecessarily doing that computation.
I know and understand the error... you're borrowing the default value inside the body of the if, but that value you're borrowing from doesn't exist outside the if. That's not my question.
Is there any cleaner way to write out this pattern?
I don't believe this is a duplicate of Is there any way to return a reference to a variable created in a function? because I have a reference I'd like to use first if possible. I don't want to dereference the reference or clone() it because that would perform unnecessary computation.
Can I store either a value or a reference in a variable at the same time?
You don't have to create the default vector if you don't use it. You just have to ensure the declaration is done outside the if block.
fn accept(input: &Vec<String>) {
let def;
let vec = if input.is_empty() {
def = vec!["empty".to_string()];
&def
} else {
input
};
// ... do something with `vec`
}
Note that you don't have to build a new default vector every time you receive an empty one. You can create it the first time this happens using lazy_static or once_cell:
#[macro_use]
extern crate lazy_static;
fn accept(input: &[String]) {
let vec = if input.is_empty() {
lazy_static! {
static ref DEFAULT: Vec<String> = vec!["empty".to_string()];
}
&DEFAULT
} else {
input
};
// use vec
}
It sounds like you may be looking for std::borrow::Cow, depending on how you're going to use it.

Get value out of optional HashMap only when present

I have a bit of code that loads a HashMap and then retrieves a value with the map.get(...) method. In my case, it's possible that I may not be able to return a HashMap, so in reality I'm dealing with an Option<HashMap>.
I've managed to isolate my problem in the following snippet:
use std::collections::HashMap;
type MyMap = HashMap<String, String>;
fn get_map() -> Option<MyMap> {
// In the real case, we may or may not be able to return a map
Some(MyMap::new())
}
fn main() {
let res = get_map().and_then(|h| h.get("foo"));
println!("{:?}", res)
}
I get the following compilation error:
error[E0597]: `h` does not live long enough
--> src/main.rs:11:38
|
11 | let res = get_map().and_then(|h| h.get("foo"));
| ^ - `h` dropped here while still borrowed
| |
| borrowed value does not live long enough
12 | println!("{:?}", res)
13 | }
| - borrowed value needs to live until here
(Playground)
I think that I get what's going on here:
The HashMap owns all of its key-value pairs.
When I call h.get(...) it lends me the value.
Because of that the HashMap needs to exist as long as the value exists.
There are really two questions here:
Am I understanding this correctly?
How do I fix this?
Call Option::as_ref. It converts an Option<T> to Option<&T>:
use std::collections::HashMap;
type MyMap = HashMap<String, String>;
fn get_map() -> Option<MyMap> {
// In the real case, we may or may not be able to return a map
Some(MyMap::new())
}
fn main() {
let map = get_map();
let res = map.as_ref().and_then(|h| h.get("foo"));
println!("{:?}", res)
}
What happened is that and_then consumes the Option; so you were trying to hold a reference to the consumed data.
The same rule applies for the returned value of get_map(): if it is not stored in its own variable, it remains a temporary value, to which you cannot hold a reference.

Why does an immutable borrow in a loop last outside of its lexical scope?

I am stuck on the borrow checker.
pub struct Gamepad {
str: String,
}
pub enum Player {
Human(Gamepad),
Computer,
}
pub struct PlayerData {
pub player: Player, /* actually this should be private */
}
struct Pong {
players: Vec<PlayerData>,
}
fn update_game(_pong: &mut Pong) {}
fn main() {
println!("Hello, world!");
let mut pong = Pong {
players: vec![
PlayerData {
player: Player::Computer,
},
PlayerData {
player: Player::Human(Gamepad {
str: "mydev".to_string(),
}),
},
],
};
game_loop(&mut pong);
}
fn game_loop(pong: &mut Pong) {
let mut vec: Vec<&Gamepad> = Vec::new();
{
for playerdata in pong.players.iter() {
match playerdata.player {
Player::Human(ref gp) => {
if gp.str == "mydev" {
vec.push(gp); //omitting this line of code fixes borrow checker issues
}
}
_ => {}
}
}
}
update_game(pong);
}
playground
This gives:
error[E0502]: cannot borrow `*pong` as mutable because `pong.players` is also borrowed as immutable
--> src/main.rs:52:17
|
41 | for playerdata in pong.players.iter() {
| ------------ immutable borrow occurs here
...
52 | update_game(pong);
| ^^^^ mutable borrow occurs here
53 | }
| - immutable borrow ends here
While I can understand the error to some extent, but coming from a C and Java background, I really struggle to get out of this problem. I am mainly confused why the immutable borrow is not released after the for loop ends. How would you write this in idiomatic Rust?
The error is a bit poorly worded, but I see your problem.
The error says the immutable borrow occurs in the for loop, which isn't quite correct. Instead, it occurs on the line you marked: vec.push(gp).
gp is an immutable reference to an object contained within pong.players. When you exit the loop, there is no immutable reference to pong.players itself, but there is a vector full of references to objects inside that vector.
pong.players : [ a, b, c, d, e]
^ ^ ^ ^ ^
vec : [&a, &b, &c, &d, &e]
Since you have outstanding immutable references to objects within pong.players, Rust has to consider pong.players as "implicitly" immutably borrowed, to ensure that none of its contents are mutated while there is still an immutable reference to that item. Since pong.players is a component of pong and is "implicitly" borrowed, pong itself has to be "implicitly" borrowed immutably as well.
In other words, the borrow of pong in game_loop lasts as such:
fn game_loop(pong: &mut Pong) {
let mut vec: Vec<&Gamepad> = Vec::new(); // <+ `vec`'s lifetime begins here
{ // |
for playerdata in pong.players.iter() { // <+ `pong.players.iter()` temporarily immutably borrows
// | `players` from `pong` for the iterator. `playerdata`
// | is a borrowed portion of `pong.players`.
// | As long as any `playerdata` exists, `pong.players`
// | is immutably borrowed by extension.
match playerdata.player { // <+ `playerdata.player` is a portion of `playerdata`.
Player::Human(ref gp) => { // <+ `gp` is a borrow of an element of `playerdata`.
if gp.str == "mydev" { // |
vec.push(gp); // <! At this point, `gp` is added to `vec`.
// | Since `gp` is inside `vec`, the reference to `gp`
// | is not dropped *until `vec` is dropped.
} // |
} // <- `gp`'s *lexical* lifetime ends here, but it may still
// | be inside `vec`. Any `gp` added to `vec` is still
// | considered borrowed.
_ => {} // |
} // <- `playerdata.player` is not longer lexically borrowed.
// | However, since `gp`, a portion of `playerdata.player`,
// | may still be borrowed, the compiler flags
// | `playerdata.player` as still borrowed.
} // <- `playerdata`'s borrow scope ends here, but since
// | `playerdata.player` may still be borrowed (due to the
// | fact that `vec` may contain references to elements of
// | playerdata.player), `playerdata` is still considered borrowed
} // <- the iterator over `pong.players` is dropped here. But since
// | `playerdata` might still be referenced in `vec`, `pong.players`
// | is still considered borrowed... and since `pong.players` is
// | implicitly borrowed, `pong` is implicitly borrowed.
update_game(pong); // <! When you reach this line, `pong` is implicitly borrowed because
// | there are references to something 'inside' it. Since you can't
// | have an immutable borrow and a mutable borrow at the same time
// | (to ensure you can't change something at the same time another
// | part of the program views it), `update_game(pong)` cannot accept
// | a mutable reference to `pong`.
} // <- At this point, `vec` is dropped, releasing all references to the
// | contents of `pong`. `pong` is also dropped here, because it is the
// | end of the function.
That explains the why. As for the how to solve it: Theoretically, the easiest solution would be to implement Clone on Gamepad (which can be easily done with #[derive(Clone)] if all of Gamepad's fields implement clone; the standard implementation is basically creating a new object by calling .clone on all of the fields of the original) and then use gp.clone() rather than just gp.
This has a (probably negligible) impact on the memory use of your program, but moreover, it can be infeasible if Gamepad uses external-library types that do not implement Clone - you can't implement Clone on those external types, because you don't define Clone or SomeExternalType in your project.
If impl Clone isn't available to you, you may need to refactor your code; reconsider why you need certain mutable or immutable borrows, and remove them if they're unnecessary. If that fails, you might need to look into other types of pointers like Cell, which I'm not qualified to give information about!
If you don't need to keep vec around and do stuff with it after update_game is called, consider this solution:
fn game_loop(pong: &mut Pong) {
{
let mut vec: Vec<&Gamepad> = Vec::new(); // <+ Vec is created
for playerdata in pong.players.iter() { // |
match playerdata.player { // |
Player::Human(ref gp) => { // |
if gp.str == "mydev" { // |
vec.push(gp); // |
} // |
} // |
_ => {} // |
} // |
} // |
for g_pad in vec { // |
// Do something with each gamepad // |
} // |
} // <- `vec` is dropped
// Since `vec` no longer exists, there are no more references
// to the contents of `pong`, and `update_game` can be called.
update_game(pong);
}
Hope this helps.

Resources