练习:表达式求值

Let’s write a simple recursive evaluator for arithmetic expressions.

The Box type here is a smart pointer, and will be covered in detail later in the course. An expression can be “boxed” with Box::new as seen in the tests. To evaluate a boxed expression, use the deref operator (*) to “unbox” it: eval(*boxed_expr).

Some expressions cannot be evaluated and will return an error. The standard Result type is an enum that represents either a successful value (Ok(Value)) or an error (Err(String)). We will cover this type in detail later.

将代码复制粘贴到 Rust Playground,然后开始实现 eval。最终结果应能通过测试。使用 todo!() 并使测试逐个通过可能会很有帮助。您还可以使用 #[ignore] 暂时跳过测试:

  1. #[test]
  2. #[ignore]
  3. fn test_value() { .. }

If you finish early, try writing a test that results in division by zero or integer overflow. How could you handle this with Result instead of a panic?

  1. #![allow(unused)]
  2. fn main() {
  3. /// An operation to perform on two subexpressions.
  4. #[derive(Debug)]
  5. enum Operation {
  6. Add,
  7. Sub,
  8. Mul,
  9. Div,
  10. }
  11. /// An expression, in tree form.
  12. #[derive(Debug)]
  13. enum Expression {
  14. /// An operation on two subexpressions.
  15. Op { op: Operation, left: Box<Expression>, right: Box<Expression> },
  16. /// A literal value
  17. Value(i64),
  18. }
  19. fn eval(e: Expression) -> Result<i64, String> {
  20. todo!()
  21. }
  22. #[test]
  23. fn test_value() {
  24. assert_eq!(eval(Expression::Value(19)), Ok(19));
  25. }
  26. #[test]
  27. fn test_sum() {
  28. assert_eq!(
  29. eval(Expression::Op {
  30. op: Operation::Add,
  31. left: Box::new(Expression::Value(10)),
  32. right: Box::new(Expression::Value(20)),
  33. }),
  34. Ok(30)
  35. );
  36. }
  37. #[test]
  38. fn test_recursion() {
  39. let term1 = Expression::Op {
  40. op: Operation::Mul,
  41. left: Box::new(Expression::Value(10)),
  42. right: Box::new(Expression::Value(9)),
  43. };
  44. let term2 = Expression::Op {
  45. op: Operation::Mul,
  46. left: Box::new(Expression::Op {
  47. op: Operation::Sub,
  48. left: Box::new(Expression::Value(3)),
  49. right: Box::new(Expression::Value(4)),
  50. }),
  51. right: Box::new(Expression::Value(5)),
  52. };
  53. assert_eq!(
  54. eval(Expression::Op {
  55. op: Operation::Add,
  56. left: Box::new(term1),
  57. right: Box::new(term2),
  58. }),
  59. Ok(85)
  60. );
  61. }
  62. #[test]
  63. fn test_error() {
  64. assert_eq!(
  65. eval(Expression::Op {
  66. op: Operation::Div,
  67. left: Box::new(Expression::Value(99)),
  68. right: Box::new(Expression::Value(0)),
  69. }),
  70. Err(String::from("division by zero"))
  71. );
  72. }
  73. }