Activity 10 - Make a Calculator with Error Handling
Goal: Build a calculator that uses Result<T, E> for error handling and Option<T> for operations.
Instructions
- Go to https://classroom.github.com/a/PJAfqzH5 to accept the assignment in github classroom. You can work together in small groups on a single repo or work on your own repo even if you are discussing with others - your choice!
- Complete the code in
src/main.rs. You will need to:- Convert string operations like "+" and "/" to an
Operationenum using a functionparse_operationthat returns anOption<Operation>. - Implement a function
calculatethat takes two numbers and anOperation, returning aResult<f64, CalcError>(which handles division by zero by returning an appropriate error). - Implement
safe_calculatorthat both parses and operator and calculates a final value, returningResult<f64, CalcError>.
- Convert string operations like "+" and "/" to an
- Run the tests using
cargo testto check your work - Run the main function to see your code in action
- Make sure to commit and push your changes to your repository!
Tips
- Use
matchstatements for pattern matching on enums - Remember that
matchmust be exhaustive (handle all cases) - For
Option<T>, useSome(value)andNone - For
Result<T, E>, useOk(value)andErr(error) - The
#[derive(Debug, PartialEq)]attributes let you print and compare enum values
Starter code
#[derive(Debug, PartialEq)] enum CalcError { DivisionByZero, InvalidOperation, } #[derive(Debug, PartialEq)] enum Operation { Add, Subtract, Multiply, Divide, } // TODO: Implement these functions fn parse_operation(op: &str) -> Option<Operation> { // Return Some(Operation) for "+", "-", "*", "/" // Return None for anything else todo!() } fn calculate(a: f64, b: f64, op: Operation) -> Result<f64, CalcError> { // Perform the calculation based on the operation // Return Err(CalcError::DivisionByZero) if dividing by zero // Hint: Check if b == 0.0 when op is Operation::Divide todo!() } fn safe_calculator(a: f64, op_str: &str, b: f64) -> Result<f64, CalcError> { // Combine parse_operation and calculate // Return Err(CalcError::InvalidOperation) if operation parsing fails // Hint: Use match on the output of parse_operation(op_str) - handle Some(operation) and None cases todo!() } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_operation() { assert_eq!(parse_operation("+"), Some(Operation::Add)); assert_eq!(parse_operation("-"), Some(Operation::Subtract)); assert_eq!(parse_operation("*"), Some(Operation::Multiply)); assert_eq!(parse_operation("/"), Some(Operation::Divide)); assert_eq!(parse_operation("x"), None); assert_eq!(parse_operation(""), None); } #[test] fn test_calculate() { assert_eq!(calculate(10.0, 5.0, Operation::Add), Ok(15.0)); assert_eq!(calculate(10.0, 3.0, Operation::Subtract), Ok(7.0)); assert_eq!(calculate(4.0, 5.0, Operation::Multiply), Ok(20.0)); assert_eq!(calculate(15.0, 3.0, Operation::Divide), Ok(5.0)); assert_eq!(calculate(10.0, 0.0, Operation::Divide), Err(CalcError::DivisionByZero)); } #[test] fn test_safe_calculator() { assert_eq!(safe_calculator(10.0, "+", 5.0), Ok(15.0)); assert_eq!(safe_calculator(10.0, "/", 0.0), Err(CalcError::DivisionByZero)); assert_eq!(safe_calculator(10.0, "x", 5.0), Err(CalcError::InvalidOperation)); } } fn main() { // Test the calculator match safe_calculator(20.0, "/", 4.0) { Ok(result) => println!("Result: {}", result), Err(CalcError::DivisionByZero) => println!("Error: Cannot divide by zero!"), Err(CalcError::InvalidOperation) => println!("Error: Invalid operation!"), } // Run tests with: cargo test }