Freddy Rangel
Freddy Rangel

Reputation: 1363

How to work with vectors of strings in Rust?

I'm working on some coding challenges to learn Rust. In JavaScript it's pretty straightforward but in Rust I've had issues.

Here's what the JS would look like:

// Decode the message by reversing the words
function reverseWords(message) {
  return message.join("").split(" ").reverse().join(" ").split("");
}

This is how far I could get in Rust solving the same problem:

// Decode the message by reversing the words
fn reverse_words(message: Vec<&str>) -> Vec<&str> {
    let temp_a = message.join("");
    let mut words: Vec<&str> = temp_a.split(" ").collect();

    words.reverse();
    let new_temp = words.join(" ");
    let result = new_temp.split("").collect();

    result
}
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn two_words() {
        let input = "thief cake".split("").collect();
        let actual = reverse_words(input).join("");
        let expected = "cake thief";

        assert_eq!(actual, expected);
    }
}

This results in the following error:

error[E0515]: cannot return value referencing local variable `new_temp`
  --> src/reverse_words/mod.rs:13:5
   |
11 |     let result = new_temp.split("").collect();
   |                  ------------------ `new_temp` is borrowed here
12 |
13 |     result
   |     ^^^^^^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.

I've tried all sorts of solutions to get around this ownership problem but there's clearly something I'm not understanding.

Here's a link to the playground if it helps: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d75a3894112c188780b9805661510c46

Upvotes: 1

Views: 1389

Answers (1)

Ian Ash
Ian Ash

Reputation: 1212

Your issue is that let new_temp = words.join(" ") is implicitly allocating memory for a String and assigning it to new_temp. The memory will be freed when the function returns as new_temp goes out of scope at that point, yet your return value is a vector of pointers into that string.

If you inspect the variables through your code, it's generally pretty confused. message in reverse_words(message: Vec<&str>) is actually coming in as a vector of single characters, not words. Then words is a collection of words, then that's being reversed and joining into a string, then finally the return value is a vector of string pointers.

I would suggest simplifying your type usage, at least initially. Start with a function definition as something simple like reverse_words(msg : String) -> String and code logic in the function that solves that case.

If you specifically want to stay with Vec<&str>, then probably easiest is to mutate the input in place, e.g. something like fn reverse_words(mut message: &Vec<&str>).

If you want to make your specific example work, the easiest way is just to return the String that was created as follows:

// Decode the message by reversing the words
fn reverse_words(message: Vec<&str>) -> String {
    let temp_a = message.join("");
    let mut words: Vec<&str> = temp_a.split(" ").collect();
    words.reverse();
    words.join(" ")
}
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn two_words() {
        let input = "thief cake".split("").collect();
        let actual = reverse_words(input);
        let expected = "cake thief";

        assert_eq!(actual, expected);
    }
}

Upvotes: 2

Related Questions