Понимание заимствований в матче с опцией

У меня есть простой парсер, который можно преобразовать в нечто вроде этого:

use std::str::Chars;
use std::iter::Peekable;

struct Parser<'a> {
    input: Peekable<Chars<'a>>,
}

impl<'a> Parser<'a> {
    fn new(input: &'a str) -> Self {
        Parser {
            input: input.chars().peekable(),
        }
    }

    fn consume(&mut self, check: char) -> bool {
        // see below
    }
}

Моя первоначальная реализация consume, которая должна смотреть на следующий символ во входных данных и возвращать true (и продвигать Peekable), если он соответствует переданному символу, была такой:

fn consume(&mut self, check: char) -> bool {
    match self.input.peek() {
        Some(c) if *c == check => {
            self.input.next();
            true
        },
        _ => false
    }
}

Компилятор сообщил мне, что я не могу заимствовать self.input для вызова next, поскольку я уже заимствовал его в вызове peek:

error[E0499]: cannot borrow `self.input` as mutable more than once at a time
  --> src/main.rs:18:17
   |
16 |         match self.input.peek() {
   |               ---------- first mutable borrow occurs here
17 |             Some(c) if *c == check => {
18 |                 self.input.next();
   |                 ^^^^^^^^^^ second mutable borrow occurs here
...
22 |         }
   |         - first borrow ends here

Я не понимаю, почему добавление & к выражению соответствия Some (и удаление * из *c) приводит к компиляции кода:

fn consume(&mut self, check: char) -> bool {
    match self.input.peek() {
        Some(&c) if c == check => {
            self.input.next();
            true
        },
        _ => false
    }
}

Основываясь на комментарии Боэтиоса, каким было бы правильное решение, если бы c не было Copy?


person Michelle Tilley    schedule 19.12.2017    source источник
comment
С помощью Some(&c) вы удаляете ссылку и делаете копию символа. С Some(c) вы сохраняете ссылку на него, что предотвращает повторное заимствование.   -  person Boiethios    schedule 19.12.2017
comment
@Boiethios Думаю, я понял, спасибо. Каким было бы идиоматическое решение, если бы c не было отмечено Copy?   -  person Michelle Tilley    schedule 19.12.2017
comment
Есть разные решения, но например: let has_matched = /*etc.*/ и после блока match: if has_matched { self.input.next() }. Когда вы застряли, промежуточная переменная часто является хорошим решением.   -  person Boiethios    schedule 19.12.2017
comment
Но, возможно, ваш дизайн не соответствует парадигме Rust. Я не могу подтвердить это, потому что я не очень хорошо разбираюсь в Rust, и у меня сейчас нет времени расследовать это дело.   -  person Boiethios    schedule 19.12.2017
comment
@Shepmaster Спасибо - ваш ответ на повторяющийся вопрос - это объяснение, которое я искал (другие ответы просто показывают альтернативы, которые Я уже изучил).   -  person Michelle Tilley    schedule 19.12.2017
comment
@MichelleTilley да, я изначально разместил это здесь, но потом нашел этот старый дубликат, поэтому переместил туда свой измененный ответ. Это помогает объяснить, почему это так хорошо подходит для ваших конкретных вопросов ;-)   -  person Shepmaster    schedule 19.12.2017