I've got a Scanner
struct that has a scan(&mut self)
method implemented. It looks like this.
pub struct Scanner {
input: String,
output: Vec<String>,
state: ScannerState,
}
impl Scanner {
pub fn scan(&mut self) {
self.state = ScannerState::CharMode;
for character in self.input.chars() {
match character {
i @ '0'...'9' => self.output.push(format!("Integer digit: {}", i)),
'+' => self.output.push("Addition operator: +".to_string()),
'-' => self.output.push("Subtraction operator: -".to_string()),
'*' => self.output.push("Multiplication operator: *".to_string()),
'/' => self.output.push("Division operator: /".to_string()),
'%' => self.output.push("Modulus operator: %".to_string()),
'^' => self.output.push("Exponent operator: ^".to_string()),
'=' => self.output.push("Assignment operator: =".to_string()),
';' => self.output.push("Statement terminator: ;".to_string()),
c @ 'a'...'z'| c @ 'A'...'Z'
=> self.output.push(format!("Variable name: {}", c)),
' ' => self.output.push("Space, ignoring.".to_string()),
z @ _ => self.output.push(format!("Unrecognized token: {}", z))
}
}
}
}
However, as you might suspect, the state of the Scanner
will change, and it will need to treat tokens differently in different states. Therefore, it would be useful to call a private method on the Scanner
from within the scan()
method itself, akin to this:
pub fn scan(&mut self) {
self.state = ScannerState::CharMode;
while self.state == ScannerState::CharMode {
for character in self.input.chars() {
self.char_match(character);
}
self.state = ScannerState::Done;
}
}
fn char_match(&mut self, c: char) {
match c {
'+' => self.output.push("Addition operator: +".to_string()),
'-' => self.output.push("Subtraction operator: -".to_string()),
'*' => self.output.push("Multiplication operator: *".to_string()),
'/' => self.output.push("Division operator: /".to_string()),
'%' => self.output.push("Modulus operator: %".to_string()),
'^' => self.output.push("Exponent operator: ^".to_string()),
'=' => self.output.push("Assignment operator: =".to_string()),
';' => self.output.push("Statement terminator: ;".to_string()),
' ' => self.output.push("Space, ignoring.".to_string()),
'q' => self.state = ScannerState::QuitMode,
i @ '0'...'9' => self.output.push(format!("Integer digit: {}", i)),
c @ 'a'...'z' => self.output.push(format!("Variable name: {}", c)),
z @ _ => self.output.push(format!("Unrecognized token: {}", z))
}
}
But wait! We can't do that, Rust tells us:
src/scanner.rs:34:17: 34:21 error: cannot borrow `*self` as mutable because `self.input` is also borrowed as immutable
src/scanner.rs:34 self.char_match(character);
^~~~
Yet our char_match()
method NEEDS to have a mutable reference to self
, since it pushes, and push()
ing on a Vec
requires mutability. My question then, is given the preceding knowledge, what is the ideal way to remedy this situation?
Will I simply have to write scan()
as a long method?