1

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

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
freddyrangel
  • 1,353
  • 1
  • 11
  • 20
  • 3
    You probably want to use a `Vec` instead of `Vec<&str>`. See https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str?r=SearchResults&s=1%7C236.9933 – Jmb Jul 31 '22 at 09:48
  • 1
    I'd also recommend to use `chars()` instead of `split("")`. – Chayim Friedman Jul 31 '22 at 09:50
  • 1
    It's not very clear what is the format of `message`. In my mind, a message could be either: a string, a vector of words of a vector of characters. But in your case, it seems like you are considering `message` to be just a vector that, when joined, makes the total message, which is weird... – jthulhu Jul 31 '22 at 11:34

1 Answers1

1

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);
    }
}
Ian Ash
  • 1,087
  • 11
  • 23
  • "I would suggest simplifying your type usage, at least initially." is great advice. Thanks for clarifying! – freddyrangel Jul 31 '22 at 10:39
  • 1
    if you want to mutate the input in place, you don't want to take a `mut message: &Vec<&str>`, but a `message: &mut [&str]`... – jthulhu Jul 31 '22 at 11:35