Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Упражнение: Замена на Result

В этом упражнении мы возвращаемся к упражнению с вычислителем выражений, которое делали во второй день. Наше первоначальное решение игнорирует возможный случай ошибки: деление на ноль! Перепишите eval, чтобы использовать идиоматичную обработку ошибок для этого случая и возвращать ошибку, когда она возникает. Мы предоставляем простой тип DivideByZeroError, который будет типом ошибки для eval.

// Copyright 2023 Google LLC
// SPDX-License-Identifier: Apache-2.0

/// Операция, которую нужно выполнить над двумя подвыражениями.
#[derive(Debug)]
enum Operation {
    Add,
    Sub,
    Mul,
    Div,
}

/// Выражение в виде дерева.
#[derive(Debug)]
enum Expression {
    /// Операция над двумя подвыражениями.
    Op { op: Operation, left: Box<Expression>, right: Box<Expression> },

    /// Литеральное значение
    Value(i64),
}

#[derive(PartialEq, Eq, Debug)]
struct DivideByZeroError;

// Исходная реализация вычислителя выражений. Обновите её, чтобы
// возвращать `Result` и создавать ошибку при делении на 0.
fn eval(e: Expression) -> i64 {
    match e {
        Expression::Op { op, left, right } => {
            let left = eval(*left);
            let right = eval(*right);
            match op {
                Operation::Add => left + right,
                Operation::Sub => left - right,
                Operation::Mul => left * right,
                Operation::Div => if right != 0 {
                    left / right
                } else {
                    panic!("Cannot divide by zero!");
                },
            }
        }
        Expression::Value(v) => v,
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[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(DivideByZeroError)
        );
    }

    #[test]
    fn test_ok() {
        let expr = Expression::Op {
            op: Operation::Sub,
            left: Box::new(Expression::Value(20)),
            right: Box::new(Expression::Value(10)),
        };
        assert_eq!(eval(expr), Ok(10));
    }
}
This slide and its sub-slides should take about 20 minutes.
  • Стартовый код здесь не совсем такой же, как решение предыдущего упражнения: мы добавили явную панику, чтобы показать студентам, где находится случай ошибки. Укажите на это, если студенты запутаются.