練習:運算式求值
我們現在要為算術運算式編寫簡單的遞迴評估器。
這裡的 Box
型別是一種智慧指標,我們會在本課程的後續部分詳細說明。如測試中所示,運算式可被 Box::new
「裝箱」。如要求裝箱運算式的值,請使用 deref 運算子 (*
) 來「開箱」:eval(*boxed_expr)
。
部分運算式無法求值,且會傳回錯誤。標準 Result<Value, String>
型別是一種列舉,用於表示成功值 (Ok(Value) )
) 或錯誤 (Err(String)
)。我們稍後會詳細說明這種型別。
請複製程式碼並貼到 Rust Playground,然後開始實作 eval
。最終成品應會通過測試。使用 todo!()
讓測試逐一通過可能有所幫助,但您也可以使用 #[ignore]
暫時略過測試:
#[test]
#[ignore]
fn test_value() { .. }
如果您提前完成操作,不妨試著編寫一個以零為除數或會整數溢位的測試。該如何利用 Result
(而非恐慌) 處理這種情況?
#![allow(unused)] fn main() { /// An operation to perform on two subexpressions. #[derive(Debug)] enum Operation { Add, Sub, Mul, Div, } /// An expression, in tree form. #[derive(Debug)] enum Expression { /// An operation on two subexpressions. Op { op: Operation, left: Box<Expression>, right: Box<Expression> }, /// A literal value Value(i64), } fn eval(e: Expression) -> Result<i64, String> { todo!() } #[test] fn test_value() { assert_eq!(eval(Expression::Value(19)), Ok(19)); } #[test] fn test_sum() { assert_eq!( eval(Expression::Op { op: Operation::Add, left: Box::new(Expression::Value(10)), right: Box::new(Expression::Value(20)), }), Ok(30) ); } #[test] fn test_recursion() { let term1 = Expression::Op { op: Operation::Mul, left: Box::new(Expression::Value(10)), right: Box::new(Expression::Value(9)), }; let term2 = Expression::Op { op: Operation::Mul, left: Box::new(Expression::Op { op: Operation::Sub, left: Box::new(Expression::Value(3)), right: Box::new(Expression::Value(4)), }), right: Box::new(Expression::Value(5)), }; assert_eq!( eval(Expression::Op { op: Operation::Add, left: Box::new(term1), right: Box::new(term2), }), Ok(85) ); } #[test] fn test_error() { assert_eq!( eval(Expression::Op { op: Operation::Div, left: Box::new(Expression::Value(99)), right: Box::new(Expression::Value(0)), }), Err(String::from("division by zero")) ); } }