Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

rust - Unable to borrow an iterator as mutable more than once at a time

I'm writing a simple tokenizer in Rust but I'm having trouble. I've simplified the code a bit for the sake of this question:

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

struct Example<'a> {
    it: Peekable<Chars<'a>>,
}

impl<'a> Example<'a> {
    fn tokenize_string(&mut self) {
        loop {
            match self.it.peek() {
                None => break,
                Some(_x) => self.it.next(),
            };
        }
    }
}

The error I'm getting is:

error[E0499]: cannot borrow `self.it` as mutable more than once at a time
  --> src/main.rs:13:29
   |
11 |             match self.it.peek() {
   |                   ------- first mutable borrow occurs here
12 |                 None => break,
13 |                 Some(_x) => self.it.next(),
   |                             ^^^^^^^ second mutable borrow occurs here
14 |             };
   |             - first borrow ends here

I've been able to work around this by creating a copy of the iterator and calling peek() on that:

fn tokenize_string(&mut self) {
    loop {
        let mut iterator = self.it.clone();
        match iterator.peek() {
            None => break,
            Some(_x) => self.it.next(),
        };
    }
}

Is this the best way to do this? It seems a little hack-ish.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Since you're working with str::chars(), and char is Copy, you can dereference to get a char instead of &char. :

fn tokenize_string(&mut self) {
    loop {
        let r = self.it.peek().cloned();
        let n = match r {
            Some(_) => self.it.next(),
            None => break,
        };
        // whatever
    }
}

If you just want to check if the iterator has returned something, use is_some():

let r = self.it.peek().is_some();
if r { ... } else { ... }

In general, however, I'm not sure if it is possible exactly in this manner without non-lexical lifetimes. You will need to put the code which checks iterator state and the code which works with the iterator based on the state with scopes, something like this:

let r = {
    // work with self.it
};
if r { ... } else { ... }

Here any references into self must not escape the lexical block in r, so there is no direct match on a value which contains references into self. There's further examples of working around this in Rust borrow of a HashMap lasts beyond the scope it's in?.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...