Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to create Vec<Vec<String>>?

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 ?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading