1
0
mirror of https://github.com/google/comprehensive-rust.git synced 2025-06-07 10:06:22 +02:00
Dustin J. Mitchell 44a79741ff
Be more consistent about tests vs. main (#2644)
The content slides all use `fn main`, with the exception of the testing
segment. But with this change, where it makes sense exercises use tests
instead, and not both tests and `fn main`.

A small change in `book.js` supports running tests when a code sample
does not have `fn main` but does have `#[test]`, so these work
naturally.

Fixes #1581.
2025-02-18 20:13:16 +00:00

118 lines
3.1 KiB
Rust

// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![allow(dead_code)]
// ANCHOR: types
/// 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),
}
#[derive(PartialEq, Eq, Debug)]
struct DivideByZeroError;
// ANCHOR_END: types
/*
// ANCHOR: eval
// The original implementation of the expression evaluator. Update this to
// return a `Result` and produce an error when dividing by 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,
}
}
// ANCHOR_END: eval
*/
// ANCHOR: solution
fn eval(e: Expression) -> Result<i64, DivideByZeroError> {
match e {
Expression::Op { op, left, right } => {
let left = eval(*left)?;
let right = eval(*right)?;
Ok(match op {
Operation::Add => left + right,
Operation::Sub => left - right,
Operation::Mul => left * right,
Operation::Div => {
if right == 0 {
return Err(DivideByZeroError);
} else {
left / right
}
}
})
}
Expression::Value(v) => Ok(v),
}
}
// ANCHOR_END: solution
// ANCHOR: tests
#[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));
}
}
// ANCHOR_END: tests