2

I'm trying to implement a simple REPL calculator in Rust and I'm hitting brick walls all over the place.

I'm consuming chars while iterating over a hardcoded string. When I hit a numeric character I want to pass control over to a function that will consume the rest of the number (assuming the number has more than one digit) and return the number, converted to an Integer.

I'm having trouble with passing Chars iterator to a function. The error I'm getting is use of moved value: 'iter'.

I understand that I can't mutate something that I gave to someone else - something that had its ownership moved - but I don't know any other way of doing this, especially since the Chars iterator is non-copyable.

#[derive(Clone, Debug)]
enum Token {
    Addition,
    Substraction,
    Multiplication,
    Division,
    Integer(i32),
    Error,
}

fn consume_number(mut iter: std::str::Chars) -> Option<i32> {
    while let Some(item) = iter.next() {
        println!("{:?}", item);
    }

    return Some(1337);
}

fn tokenize(line: &str) -> Vec<Token> {
    let mut iter = line.chars();
    let mut tokens = Vec::new();
    let mut token;

    while let Some(c) = iter.next() {
        if c.is_whitespace() { continue };

        if c.is_digit(10) {
            token = match consume_number(iter) {
                Some(i32) => Token::Integer(i32),
                None => Token::Error,
            };
        } else {
            token = match c {
                '+'                    => Token::Addition,
                '-'                    => Token::Substraction,
                '*'                    => Token::Multiplication,
                '/'                    => Token::Division,
                _                      => Token::Error,
            };
        };
        tokens.push(token);
    }
    return tokens;
}



fn main() {
    let line = "631 * 32 + 212 - 15 / 89";
    println!("{:?}", tokenize(&line));
}
neektza
  • 483
  • 6
  • 11

1 Answers1

6

The answer is yes, it's done in the FromIterator trait.

What you experience here is much more basic:

fn consume_number(mut iter: std::str::Chars) -> Option<i32> { ... }

while let Some(c) = iter.next() {
    ...
    match_consume_number(iter)
    ...
}

When calling match_consume_number you are transferring ownership of the iterator to it. It means that at the next iteration of the loop body, this iter variable is no longer available.

If the iterator is meant to still be usable afterward, you should pass a reference to it:

fn consume_number(iter: &mut std::str::Chars) -> Option<i32> { ... }

while let Some(c) = iter.next() {
    ...
    match_consume_number(&mut iter)
    ...
}

You were close!

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thank you very very much kind sir! – neektza Feb 12 '16 at 09:10
  • 1
    BTW how did you know that the problem was that the iter was going out of scope in the while loop? What gave it away? What should I have been looking for? – neektza Feb 12 '16 at 09:11
  • 2
    `use of moved value: 'iter'.` means that the ownership of `iter` was transferred to something else. "move" in Rust means "transfer ownership". You'll get used to it ;) – Matthieu M. Feb 12 '16 at 09:14
  • 1
    @neektza: The `iter` didn't "go out of scope", though, that's a different notion. When you try to use an identifier that's "out of scope", you get an "unresolved name" error. That's not what happened here! – Francis Gagné Feb 12 '16 at 13:15