I decided to try and complete the Parsing/RPN calculator algorithm from Rosetta Code in Rust. I'm still learning Rust and would appreciate feedback on my code.
use std::str::FromStr;
fn rpn(expression: &str) -> f64 {
let mut stack: Vec<f64> = Vec::new();
let tokens: Vec<&str> = expression.split_whitespace().collect();
for token in tokens {
match token {
"+" => {
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
stack.push(a + b);
},
"-" => {
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
stack.push(a - b);
},
"*" => {
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
stack.push(a * b);
},
"/" => {
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
stack.push(a / b);
},
"^" => {
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
stack.push(a.powf(b));
},
_ => {
stack.push(f64::from_str(token).unwrap());
}
}
}
stack.pop().unwrap()
}
fn main() {
let expression = "3 4 2 * 1 5 - 2 3 ^ ^ / +";
println!("{}", rpn(expression));
}
I had attempted to write the commutative operations without assigning the operands to variables (i.e. a
and b
) like this:
stack.push(stack.pop().unwrap() + stack.pop().unwrap());
However, I received:
error: cannot borrow `stack` as mutable more than once at a time [E0499]
Another Approach
One approach I noticed some of the other languages' implementations using was to first check if a token is a number and push it onto the stack before checking for the operations. This allowed them to pop the two operands for the operations after they were sure it wasn't a number.
fn rpn(expression: &str) -> f64 {
let mut stack: Vec<f64> = Vec::new();
for token in expression.split_whitespace() {
let value = token.parse::<f64>();
if value.is_ok() {
stack.push(value.unwrap());
continue;
}
let b = stack.pop().unwrap();
let a = stack.pop().unwrap();
match token {
"+" => stack.push(a + b),
"-" => stack.push(a - b),
"*" => stack.push(a * b),
"/" => stack.push(a / b),
"^" => stack.push(a.powf(b)),
_ => {}
}
}
stack.pop().unwrap()
}