0

I'm implementing a parser combinator library:

#[derive(Debug)]
enum Parser {
    Char(char),
    Positive(Box<Parser>),
}

impl Parser {
    fn run(self, s: &str) -> (bool, &str) {
        match self {
            Parser::Char(ch) => {
                if s[0..1].chars().next().unwrap() == ch {
                    (true, &s[1..])
                } else {
                    (false, s)
                }
            }

            Parser::Positive(parser) => {
                //println!("{:?}", parser);
                let mut s = s;
                let mut res = (false, s);
                let parser = *parser;

                loop {
                    let ret = parser.run(s);
                    if !ret.0 {
                        break;
                    }

                    res = ret;
                    s = res.1
                }

                res
            }
            _ => (false, s),
        }
    }
}

pub fn run() {
    let x = Parser::Positive(Box::new(Parser::Char('a')));
    let ret = x.run("aaa");

    println!("{} {}", ret.0, ret.1);
}

I'm getting the error

error[E0382]: use of moved value: `parser`
  --> src/lib.rs:25:31
   |
22 |                 let parser = *parser;
   |                     ------ move occurs because `parser` has type `Parser`, which does not implement the `Copy` trait
...
25 |                     let ret = parser.run(s);
   |                               ^^^^^^ value moved here, in previous iteration of loop

I have no idea why this happens. I've tried to add the Copy trait to the Parser enum, but this causes other errors. Why can't I call parser.run() in a loop, or even twice? A single call compiles and runs perfectly.

Would it be better to use a struct instead of an enum?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
glasflügel
  • 325
  • 2
  • 11
  • 2
    Why have you chosen to take `self` instead of `&self`? See [When would an implementation want to take ownership of self in Rust?](https://stackoverflow.com/q/36531671/155423) – Shepmaster Nov 07 '19 at 00:17
  • It looks like your question might be answered by the answers of [How to prevent a value from being moved?](https://stackoverflow.com/q/41664099/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Nov 07 '19 at 00:17
  • How does this question differ from [Option Moved in Previous Loop Iteration](https://stackoverflow.com/q/54993331/155423); [Value moved here, in previous iteration of loop](https://stackoverflow.com/q/58730100/155423); [How can I solve “use of moved value” and “which does not implement the `Copy` trait”?](https://stackoverflow.com/q/49309847/155423); etc.? – Shepmaster Nov 07 '19 at 00:19
  • hello @Shepmaster, I really don't know why I didn't use &self, because I thought I don't want to change anything on the parser object. When I use &self, I'm facing other problems which I can't follow. – glasflügel Nov 07 '19 at 08:30
  • To anyone learning Rust after learning other programming languages: Assignment (`=`) in Rust is a different beast altogether. It transfers responsibility for the lifetime of the object along with the object, making the previous name you had for it obsolete and unusable. – Roger Dahl Feb 14 '21 at 20:53

1 Answers1

1

OK, changed the function's signature to

fn run<'a>(&self, s: &'a str) -> (bool, &'a str)

now and needed some other lines to be fixed.

Works now, but I don't know why.

glasflügel
  • 325
  • 2
  • 11
  • 1
    You might want to read the Rust book, especially chapters 5.2 and 5.3 on when to use `self/&self/&mut self`. – justinas Nov 08 '19 at 09:48
  • 1
    Have you tried borrowing a mutable reference to self? ```&mut self```. Declaring this in the function definition will guarantee that your function will not own self. Had this problem in one of my mods. I declared a struct, then called a function on it every loop, and got this same error. – VocoJax Nov 30 '19 at 20:25