我有一个Scanner
已实现scan(&mut self)
方法的结构。看起来像这样。
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))
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是,您可能会怀疑,状态Scanner
会改变,并且在不同状态下需要对令牌进行不同的处理。因此,类似于下面这样,Scanner
从scan()
方法本身内部调用的私有方法将很有用:
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))
}
}
Run Code Online (Sandbox Code Playgroud)
可是等等!Rust无法告诉我们:
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);
^~~~
Run Code Online (Sandbox Code Playgroud)
然而,我们的char_match()
方法需要对进行可变引用self
,因为它推送并push()
基于Vec
要求是可变的。那么,给我的问题是,根据先前的知识,解决这种情况的理想方法是什么?
我是否只需写scan()
一个长方法?
我的建议是无国籍char_match
:
pub fn scan(&mut self) {
self.state = ScannerState::CharMode;
while self.state == ScannerState::CharMode {
for character in self.input.chars() {
match char_match(character) {
Some(string) => self.output.push(string),
None => self.state = ScannerState::QuitMode
}
}
self.state = ScannerState::Done;
}
}
fn char_match(c: char) -> Option<String> {
Some(match c {
'+' => "Addition operator: +".into(),
'-' => "Subtraction operator: -".into(),
'*' => "Multiplication operator: *".into(),
'/' => "Division operator: /".into(),
'%' => "Modulus operator: %".into(),
'^' => "Exponent operator: ^".into(),
'=' => "Assignment operator: =".into(),
';' => "Statement terminator: ;".into(),
' ' => "Space, ignoring.".into(),
'q' => return None,
i @ '0'...'9' => format!("Integer digit: {}", i),
c @ 'a'...'z' => format!("Variable name: {}", c),
z @ _ => format!("Unrecognized token: {}", z)
})
}
Run Code Online (Sandbox Code Playgroud)
这完全避免了借用,并且也更可组合。