Nom crate, reusing locally created parsers, use of moved value error

I'm getting into using nom, and I made the following parsers:

let colon = char::<_, nom::error::Error<_>>(',');
let int = map_res(is_not(","), |f: &str| f.parse::<Integer>());

Which then I tried to use like this:

let (s, (x, _, y, _)) = tuple((int, colon, int, colon))(s).unwrap();

But the compiler tells me that the values int and colon cannot be used again since it was moved:


I followed the example here which seems to be reusing multiple locally created parsers but I can't seem to recreate something like that.

Can anybody who's familiar with the nom crate help me with this issue?

Parser is implemented for any FnMut, but only a shared reference to a Fn is a FnMut, and map_res does not return a Fn. Therefore, you cannot put multiple references to int in a tuple through borrowing, and you cannot copy it since FnMut is not Clone. Instead, you can use basic generator functions that create separate parser objects:

let colon = || char::<_, nom::error::Error<_>>(',');
let int = || map_res(is_not(","), |f: &str| f.parse::<i32>());
let (s, (x, _, y, _)) = tuple((int(), colon(), int(), colon()))(s).unwrap();
4 Likes

To give some background on this: closures aren't just functions. They're combinations of functions and data they can access. The captured data could be something non-copyable (e.g. an exclusive reference, which can't be copied, because it would stop being exclusive), so the compiler can't automatically assume closures are copyable.

Additionally, in generic code it doesn't matter what the code actually does, it only matters what the generic bounds say the code could do. In case of nom, it says closures could have non-copyable data (they're not marked as Copy), so all of them, generically, are treated as such.

5 Likes

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.