3
votes

I am trying to write some Rust code using some iterator magic, but I have a problem with double references and Rust's documentation:

#[derive(PartialEq,Eq)]
pub enum Token {
    ECOND,
    SCOND
}

pub fn validate(pgm: &Vec<Token>) -> Result<(), ()> {
    let valid1 = pgm.iter()
                    .filter(|&&item|
                        item == Token::SCOND || item == Token::ECOND
                    )
                    .fold(0, |acc: i64, ref x| -> i64 {
                        if x == &&Token::SCOND {
                            return acc + 1;
                        } else {
                            return acc - 1;
                        }
                    });

    if valid1 != 0 {
        return Err(());
    }
    return Ok(());
}

It gives me an error :

error: cannot move out of borrowed content [E0507]
                        .filter(|&&item|
                              ^~~~~
help: run `rustc --explain E0507` to see a detailed explanation
note: attempting to move value to here
                        .filter(|&&item|
                               ^~~~
help: to prevent the move, use `ref item` or `ref mut item` to capture value by reference

As stated by filter's doc, with double references I can write the code these ways, and it works:

.filter(|&item|
    *item == Token::SCOND || *item == Token::ECOND
)

And also like that:

.filter(|item|
    **item == Token::SCOND || **item == Token::ECOND
)

But how can I use my solution (which is also the doc solution)? I don't see where is my mistake.

1

1 Answers

3
votes

The main difference between your Token and the doc's i32 is that a i32 is Copy.

Rust types are, by default, affine types: they may at most be used (transferred by value) once. Copy types are the exception to the rule, they can be used any number of times, because using them does not transfer ownership, it silently produces a Clone instead.

As a result, unless your Token type is made Copy (which also requires Clone), you cannot use the third form presented in the documentation of filter.

You can simply use:

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Token { .... }

to make it Copy, or not use the third form. I would advise the latter unless you are comfortable guaranteeing to your clients that it will remain Copy.