Nom returning refs

I want to parse some string constants with nom5 the constants

would be like


I can obviously match these with something like

alt((tag("today"), tag("yesterday"), tag("thisweek"), tag("thismonth"), tag("thisyear"))

but I want to map these to a a date string.

today -> "13-08-2020"
thismonth -> "01-08-2020"

so something like

fn date_const_s<'a>(i: &'a str) -> IResult<&'a str, &'a str, (&'a str, ErrorKind)> {
    map(alt((tag("today"), tag("yesterday"), tag("thisweek"), tag("thismonth"), tag("thisyear"))), 
        |s: &str| 
            match s.as_ref() {
                "today" => Utc::today().to_string().as_ref(),
        } )(i)

I have two issues I don't know how to solve though.
The first is how I can return a string ref without creating a temporary with to_string()
and how can I return an Err if the match does not succeed as I would have different types in different arms on the match ?


Returning a string ref from this function isn’t going to be possible(1). The reference would need to point into i somewhere, but the string you want to return, "2020-08-13" doesn’t appear as a substring of i ("today")— You’ll need to make the return type be a String instead of an &str.


(1) Not entirely true, there’s always a way. Here, you could use Box::leak, but it’s a bad idea. You get unbounded memory usage for almost no benefit.


As far as returning an error, if you want the closure to be fallible, use map_res instead of map. If you just need to include an _ arm to make the compiler happy since you're already handling all the variants, you can use _ => unreachable!() which will panic if its reached.

Just a slight something to add, because it's a common problem. I've run into it myself more times than I care to admit! :smiley:

You can't return a reference to something created inside a function.

The 'something' will drop out of scope when the function ends, so what would your reference be pointing to?

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.