I like experimenting with Rust, but something doesn’t always work for me, so as part of a new API project, I prepared a code that I thought would work.
I need to execute above code
let mut rows: Vec<Vec<&String>> = Vec::new();
{
let grade_string: String = String::from("Example Title");
let grade_category_string: String = String::from("Example Message");
let mut pos_row: Vec<&String> = Vec::new();
pos_row.push(&grade_string);
pos_row.push(&grade_category_string);
rows.push(pos_row);
}
And gets error
error[E0597]: `grade_string` does not live long enough
--> src/lib/functions.rs:25:26
|
21 | let grade_string: String = String::from("Example Title");
| ------------ binding `grade_string` declared here
...
25 | pos_row.push(&grade_string);
| ^^^^^^^^^^^^^ borrowed value does not live long enough
...
28 | rows.push(pos_row);
| ---- borrow later used here
...
31 | }
| - `grade_string` dropped here while still borrowed
error[E0597]: `grade_category_string` does not live long enough
--> src/lib/functions.rs:26:26
|
22 | let grade_category_string: String = String::from("Example Message");
| --------------------- binding `grade_category_string` declared here
...
26 | pos_row.push(&grade_category_string);
| ^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
27 |
28 | rows.push(pos_row);
| ---- borrow later used here
...
31 | }
| - `grade_category_string` dropped here while still borrowed
How can I execute the command without problem ?
>Solution :
Let’s take a look at what’s going on:
let mut rows: Vec<Vec<&String>> = Vec::new();
{
// You are defining two strings.
// Like every other data structure in Rust, these strings are created within
// a scope (delimited here by the curly braces).
//
// If you don't move (or perhaps copy) them out of the scope or wrap them
// within a data structure that is going to be moved or copied out of the
// scope, they'll be deallocated, their destructor is going to run, etc.
let grade_string: String = String::from("Example Title");
let grade_category_string: String = String::from("Example Message");
// Here, you're informing Rust that you want a vector of _references_
// to strings. References do not copy, do not move, they're just shortcuts
// to things that are already in memory.
let mut pos_row: Vec<&String> = Vec::new();
// Here, you're adding references to your strings.
// They're not keeping the string alive, just let you access them quickly.
pos_row.push(&grade_string);
pos_row.push(&grade_category_string);
rows.push(pos_row);
// We've reached the end of the scope. Everything that is bound to this
// scope will now be deallocated. That's your two strings `grade_string`
// and `grade_category_string`.
}
// At this point, if Rust accepted your code, `rows` would contain to
// references to strings that do not exist anymore. Using them would
// cause memory corruption (that's what would happen in most non-garbage
// collected languages).
In this case, we can fix the problem easily, by moving the Strings out
of the scope. To do that, just don’t tell Rust that you want a reference!
let mut rows: Vec<Vec<String>> = Vec::new(); // <- Removed the `&`.
{
// Define two strings in the current scope.
let grade_string: String = String::from("Example Title");
let grade_category_string: String = String::from("Example Message");
// Here, you're informing Rust that you want a vector of `String`.
// This vector will also live only until the end of the scope.
let mut pos_row: Vec<String> = Vec::new(); // <- Removed the `&`.
// Move your strings into `pos_row`.
pos_row.push(grade_string); // <- Removed the `&`.
pos_row.push(grade_category_string); // <- Removed the `&`.
// At this point, `grade_string` and `grade_category_string` don't
// exist anymore. You could check that by attempting to println
// them, for instance: Rust won't let you because they've been moved.
// Move `pos_row` into `rows`.
rows.push(pos_row);
// Similarly, at this point, `pos_row` doesn't exist anymore.
// We've reached the end of the scope. Everything that is bound to this
// scope will now be deallocated. As it turns out, there is nothing bound
// to this scope, so nothing happens.
}
// At this point, `rows` is still alive and contains all the data you want!
As a side-note, you could write something slightly more compact:
let mut rows = vec![]; // Rust will infer the type.
{
let pos_row = vec![ // Rust will infer the type.
String::from("Example Title"),
String::from("Example Message")
]; // Note that `pos_row` is not declared `mut` since we never actually modify it anymore.
rows.push(pos_row);
}
You could even factor this into a single statement if you wanted.