The critical difference between &str
and String
is ownership. String
is owned, but &str
is borrowed. If you store a &str
value, the container's lifetime will be limited to the lifetime of the borrowed string.
If your parser generator produces a parse function with a signature like this:
smtp_parser::host<'a>(&'a str) -> SmtpHost<'a>
then when it passes you an &str
for you to use to construct your parse tree/parsed value, it most likely gives you a substring of the input. This means that the &str
you are storing in your SmtpHost
enum must have a lifetime shorter than the original input string. And indeed, you can see this in the signature; both the input string and output SmtpHost
have lifetime parameter 'a
.
This means that your resulting SmtpHost
cannot outlive the input used to generate it. If the input is a string constant, &'static str
, that might be fine, but if you get the input from standard in or reading a file, you won't be able to return the SmtpHost
past the point where the input string is owned.
For example, suppose that you wanted to declare a function that parsed an SmtpHost
from standard in:
fn read_host<'a>() -> SmtpHost<'a> {
let mut line = String::new();
let stdin = io::stdin();
stdin.lock().read_line(&mut line).expect("Could not read line");
smtp_parser::host(&line)
}
You'll get an error saying something like "line does not live long enough". Here's a trivial example in Rust playground.
So you should use &str
when you are just borrowing a value from somewhere else which does not need to outlive the source. You should use String
when you need to have ownership of the value.
For more complex situations where you need to have an owned value but want to be able to use it in multiple places without having many copies of it, for that there's Rc<T>
and Rc<RefCell<T>
. But in your case, it sounds like SmtpHost
should just have ownership of the string it stores.
CamelCase
, notFULLCAPS
. You might have a specific reason to do this, in which case I apologize. But if not, just stick with the convention :)&str
is not owned, so if you want to be able to keep your tokens around after the parser finishes, you probably have to useString
smtp_parser::host< 'input >(s: 'input & str) -> SmtpHost
SmtpHost
using&str
with that lifetime parameter then the returnedSmtpHost
would have to have a lifetime which is <='input
, since it the signature would have to be:smtp_parser::host<'input>(s: &'input str) -> SmtpHost<'input>
. Just useString
unless you have a specific reason that these values should be borrowing part of a different string; it looks to me like they should own the matched values.