Temporary value is freed at the end of this statement [duplicate] - rust

This question already has answers here:
"borrowed value does not live long enough" when using the builder pattern
(1 answer)
"borrowed value does not live long enough" seems to blame the wrong thing
(2 answers)
Why is it legal to borrow a temporary?
(3 answers)
Why does the compiler tell me to consider using a `let` binding" when I already am?
(2 answers)
Closed 4 years ago.
I'm trying to scrape a webpage using the Select crate:
let document = Document::from_read(response).unwrap();
for node in document.find(Class("lia-list-row")) {
let title = node.find(Class("page-link")).next().unwrap();
let title_text = title.text().trim();
println!("{}\n", title_text);
}
Which results in following error:
let title_text = title.text().trim();
^^^^^^^^^^^^ - temporary value is freed at the end of this statement
|
creates a temporary which is freed while still in use
println!("{} - {}\n", i, title_text);
---------- borrow used here, in later iteration of loop
I solved it by separating the .text() and .trim()
let title_text = title.text();
let trim_text = title_text.trim();
What is the difference? Why did the first attempt fail?

This one seems convoluted at first, but remember that String and &str are different beasts.
String can live and be used on its own, but &str is just a reference to part of String. So, &str can live as long as referenced String lives. Lets see how it should work on return signatures.
let title_text = title .text() .trim();
// ^ ^ ^
// Node String <- &str
Here, title is a select::Node.
Node::text returns a String, but nothing binds it to context.
String::trim, in turn, returns a &str which is a reference to part of String itself.
In the end, the borrow checker just doesn't understand how it should process a reference to String that will not live long enough in context, as it is a temporary value (non-bound).

Related

Isn't there a way to give a value to a vector without any "strings attached" / without borrowing? [duplicate]

This question already has answers here:
What are the differences between Rust's `String` and `str`?
(14 answers)
Closed 6 months ago.
Need help to make this work. I thought clone() would make a deep copy of my string. Then getting the literal-string of it would just be a value ... not linked to any variable?
fn main() {
let mut keep_vec: Vec<&str> = vec![];
let new_string = "New String".to_string();
// create a new string inside an expression
// and push it into the keep_vec
{
let second_string = "Second String".to_string();
/* created this after I got ERROR:
temporary value dropped while borrowed E0716
creates a temporary which is freed while still
in use Note: consider using a `let` binding to
create a longer lived value
*/
let string_clone = second_string.clone();
/* now getting this ERROR:
`string_clone` does not live long enough E0597
borrowed value does not live long enough
*/
keep_vec.push(string_clone.as_str());
}
keep_vec.push(&*new_string);
}
Here is a link to the Rust Playground.
&str is not an owned type. It is a reference to a string stored somewhere else.
String is the owned type that actually contains the data.
fn main() {
let mut keep_vec: Vec<String> = vec![];
let new_string = "New String".to_string();
// create a new string inside an expression
// and push it into the keep_vec
{
let second_string = "Second String".to_string();
keep_vec.push(second_string);
}
keep_vec.push(new_string);
}
There is no need to clone() your strings. to_string() already creates a String which owns its content. You can simply move it into the vector.
Your problem was that Vec<&str> cannot hold any data, because it's a vector of references. If you want a vector that actually holds its string values, it needs to be a Vec<String>.
getting the literal-string of it would just be a value
I think you misunderstand what a "string literal" is.
Here a quick recap, although this is already mentioned in the duplicate:
String - owns its content, doesn't borrow anything. Can get created via "bla".to_string().
&str - reference to (part of) another string, doesn't own its content. The data it references has to outlive it.
&'static str - A string literal. A reference to a string that is stored in const static memory, is immutable and valid throughout the entire program. Like "bla". (Disclaimer: other things that are not string literals could also be &'static str; this is oversimplified to make it easier to digest for Rust beginners)

why do I need to use `let` binding [duplicate]

This question already has answers here:
Why does the compiler tell me to consider using a `let` binding" when I already am?
(2 answers)
Closed last year.
While trying to print out my home directory I came across the following error:
fn main() {
let home = home::home_dir().unwrap().to_str().unwrap();
println!("home dir: {}", home);
}
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:3:16
|
3 | let home = home::home_dir().unwrap().to_str().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
4 | println!("home dir: {}", home);
| ---- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
But if I split the part underlined in the error message and put it in a separate variable it works:
fn main() {
let home_buf = home::home_dir().unwrap();
let home_str = home_buf.to_str().unwrap();
println!("home dir: {}", home_str);
}
My question is what's the difference between the two examples?
(I'm using the home crate in my code)
home::home_dir().unwrap() provides a std::path::PathBuf.
Invoking .to_str().unwrap() provides a reference to something that is stored inside the preceding PathBuf.
Thus, for the reference to be valid, the PathBuf must exist (and Rust enforces that).
In your first expression, the PathBuf is a temporary that will be dropped straight away; the reference home would be dangling! (it's an error).
In your second example, the home_buf binding keeps the PathBuf alive, then the reference home_str can be used as long as home_buf exists.
Another way to look at it is that your original code is roughly equivalent to:
fn main() {
let home;
{
let tmp1: Option<PathBuf> = home::home_dir();
let tmp2: PathBuf = tmp1.unwrap();
let tmp3: Option<&str> = tmp2.to_str();
home = tmp3.unwrap();
}
println!("home dir: {}", home);
}
In other words, all the temporary values created by an expression last as long as the expression, and no longer than that. Storing a reference that borrows from tmp2 into home is not allowed because, the reference would then outlive the value it borrows from.
By introducing a variable to hold the PathBuf, you made it last longer than the expression, and the reference becomes valid.

Lack of lifetime of line from buffered reader prevents splitting line

I am banging my head trying to figure out Rust's borrowing/lifetime/ownership properties. Namely, when using a buffered reader, and attempting to split a line. The code
use std::fs::File;
use std::io::{BufRead, BufReader};
fn main() {
let f = File::open("foo.txt").expect("file not found");
let f = BufReader::new(f);
for line in f.lines() {
let split: Vec<&str> = {
let ln: String = line.unwrap();
ln.split(' ').collect()
};
}
}
or any variation of (with or without specifying variable type, futile attempts to make it mutable, etc) results in:
'ln' does not live long enough; borrowed value must only be valid for the static lifetime...
yet trying to maybe fake an extended lifetime and grab some data out of the line via a slice
let nm = line;
name = &line[..];
or even just trying to operate the split() on the unmodified line variable results in:
cannot index into a value of type 'std::result::Result<std::string::String, std::io::Error>'
"borrowed value does not live long enough" seems to blame the wrong thing suggests that the lifetime lasts long enough to put each word into its own string, but modifying my original code on the Playground to include that nested for loop still results in a
error[E0597]: borrowed value does not live long enough
--> src/main.rs:11:18
|
11 | for w in line.unwrap().split_whitespace() {
| ^^^^^^^^^^^^^ temporary value does not live long enough
...
14 | }
| - temporary value dropped here while still borrowed
15 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
in reference to the line.unwrap()
Ultimately, what am I misunderstanding here about Rust's lifetime or borrowing properties?
The error your original code gives when compiled is:
error[E0597]: `ln` does not live long enough
--> src/main.rs:11:13
|
11 | ln.split(' ').collect()
| ^^ borrowed value does not live long enough
12 | };
| - `ln` dropped here while still borrowed
13 | }
| - borrowed value needs to live until here
error: aborting due to previous error
As per #shepmasters comments it is a good idea to provide the full error when posting a question.
Anyway, it highlights the problem:
let split: Vec<&str> = {
let ln: String = line.unwrap();
ln.split(' ').collect()
};
You are creating a Vec containing references to str slices; slices don't own the data that they are sliced from, they are effectively pointers into data which has to be owned by another variable. Therefore the variable that they are sliced from have to outlive the slices.
Inside the expression you are using to initialise the Vec, you create a String containing the line of text that you are processing. The scope of this string is the variable ln is the initialisation expression - it will be dropped as soon as you leave that scope.
Then you split the string, which returns an iterator to string slices, one per substring. Remember though, the iterator is returning slices, which are pointers to the substrings in the String ln. Those slices are not allowed to outlive ln itself.
Hopefully you can see the problem now. As soon as you exit the initialisation expression, ln is dropped, but the Vec would still contain the str slices. What are they pointing to?
The fix is very simple. Why declare ln inside that block? In fact why have a block there at all? This works:
for line in f.lines() {
let ln: String = line.unwrap();
let split: Vec<&str> = ln.split(' ').collect();
// Now do something with split
}

The trait `std::marker::Sized` is not implemented for `[u16]` [duplicate]

This question already has answers here:
What is the return type of the indexing operation?
(2 answers)
How to get subslices?
(1 answer)
Closed 5 years ago.
I have a function that converts a wide string array as a [u16] to a String.
fn get_string_from_wide(wide_array: &[u16]) -> Result<String, String> {
let trimmed_wide = wide_array.iter()
.position(|char| *char == 0)
.map(|i| &wide_array[..i]) //<- remove `&` will give the error as the title
.unwrap_or(wide_array);
let os_str = OsString::from_wide(trimmed_wide);
os_str
.into_string()
.or(Err("Could not convert `Os_String` to `String`".to_string()))
}
Although the parameter is passed by reference, I still get the type as [u16] instead of &[u16]
If I remove the & the code compiles, but I don't want to pass a reference of a reference.
Is the var wide_array actually the data itself and not a reference as stated in the function parameter, and thus I still need to take a reference with & for referenced function calls? Or is it actually a reference to it?

rust: cannot move out of indexed context [duplicate]

This question already has answers here:
What does "cannot move out of index of" mean?
(2 answers)
Closed 6 years ago.
I'm very new to rust, and am starting to get the hang of the ownership system and such, but am still having some hangups. For exmaple, I have the following code:
fn main() {
let mut t = vec![Box::new(4)];
let mut o = t[0];
*o = *o + 1;
t[0] = o;
println!("t[0]:{}", t[0]);
}
Which gives me the cannot move out of indexed content error for the line where I'm initializing o. I understand why this is happening, I think, but I can't figure out what I'm supposed to do instead to accomplish the same thing. This is a very simplified case, but any help would be greatly appreciated. Thanks!
The expression t[0] is equivalent to either *t.index(0) or *t.index_mut(0), based on context. These methods return an immutable reference and a mutable reference, respectively. The indexing operator automatically dereferences these.
Since you have a vector of Box<i32>, dereferencing is not valid, because that would try to move the value from the vector. But then, what do you put in the vector in its place?
Instead of trying to move the value, you need to use a reference to the value instead. Also, if you want to be able to add 1 to the value, you need a reference to the value, not a reference to the Box. You can do this by first dereferencing the box, then by taking a mutable reference to the result:
fn main() {
let mut t = vec![Box::new(4)];
{
let o = &mut *t[0];
*o = *o + 1;
}
println!("t[0]:{}", &t[0]);
}
I had to add a block here to make the mutable borrow end before the println!, otherwise the compiler complained with:
error: cannot borrow `t` as immutable because it is also borrowed as mutable
Also, notice how we don't need to put the updated value back in the vector, because we changed the value in the vector directly by using a reference to it.

Resources