0

just starting out on my adventures in Rust and trying to figure out the right way to create and return an enum that should take ownership of a &str string slice created from a String passed into the method. I don't think lifetime annotations in and of themselves will solve the problem since the original string argument will go out of scope at the end of the function block regardless. Any help would be much appreciated.

pub enum PubSubMessage {
    // For now I won't worry about subbing/unsubbing to an array of channels
    SUBSCRIBE { channel: &str },
    UNSUBSCRIBE { channel: &str },
    PUBLISH { channel: &str, msg: &str},
    PSUBSCRIBE { pattern: &str },
    PUNSUBSCRIBE { pattern: &str},
}

pub fn parse_message(msg: String) -> Result<PubSubMessage, String> {
    let msg_contents: Vec<&str> = msg.split(" ").collect();

    return match msg_contents.as_slice() {
        ["SUBSCRBE", channel] => Ok(PubSubMessage::SUBSCRIBE { channel }),
        ["UNSUBSCRIBE", channel] => Ok(PubSubMessage::UNSUBSCRIBE { channel }),
        ["PUBLISH", channel, msg] => Ok(PubSubMessage::PUBLISH { channel, msg }),
        _ => Err("Could not parse ws message.".to_string())
    }
}

The current compiler error that I'm getting is just that the enum definition expects lifetime parameters.

  • 1
    If you want ownership, you'd generally leave the value as a `String`. What's the motivation for wanting `&str` here? The function signature, as you've defined it, is not possible because there isn't anywhere to borrow from that is left alive after the function call. – loganfsmyth Dec 09 '19 at 00:54
  • 1
    Does this answer your question? [Return local String as a slice (&str)](https://stackoverflow.com/questions/29428227/return-local-string-as-a-slice-str) – trent Dec 09 '19 at 01:25
  • 1
    tl;dr: use `String` for owned strings. – trent Dec 09 '19 at 01:29
  • There are many other versions of this question. [Is there any way to return a reference to a variable created in a function?](https://stackoverflow.com/q/32682876/3650362) is one. [How to return a instance of a struct that uses a locally declared variable](https://stackoverflow.com/q/43857098/3650362) and [How to solve “returns a value referencing data owned by the current function” error in Rust?](https://stackoverflow.com/q/54758052/3650362) are a little closer to your case. – trent Dec 09 '19 at 01:43

1 Answers1

2

As others have said in the comments, the easiest way to do it is to use String everywhere. That being said, if you wan to avoid extra copies and allocations, you can push the responsibility for owning the string higher up the call chain. If you want to do that, you will need to change your function signature so that it borrows msg instead of taking ownership, and add the required lifetime parameters. Something like this:

pub enum PubSubMessage<'a> {
    // For now I won't worry about subbing/unsubbing to an array of channels
    SUBSCRIBE { channel: &'a str },
    UNSUBSCRIBE { channel: &'a str },
    PUBLISH { channel: &'a str, msg: &'a str},
    PSUBSCRIBE { pattern: &'a str },
    PUNSUBSCRIBE { pattern: &'a str},
}

pub fn parse_message<'a> (msg: &'a str) -> Result<PubSubMessage<'a>, String> {
    let msg_contents: Vec<_> = msg.split(" ").collect();

    return match msg_contents.as_slice() {
        ["SUBSCRBE", channel] => Ok(PubSubMessage::SUBSCRIBE { channel }),
        ["UNSUBSCRIBE", channel] => Ok(PubSubMessage::UNSUBSCRIBE { channel }),
        ["PUBLISH", channel, msg] => Ok(PubSubMessage::PUBLISH { channel, msg }),
        _ => Err("Could not parse ws message.".to_string())
    }
}

Playground

Jmb
  • 18,893
  • 2
  • 28
  • 55