Post

Learning Rust Ep.3

Learning Rust Ep.3

Learning Rust Ep.3

Welcome back!

Today I decided to take a look at a super simple beginner project: a simple calculator. This was a great way to get a feel for the language and to start to understand how to structure a project.

The Project

The project is a simple calculator that can add, subtract, multiply and divide N numbers. It is interesting because it uses “lambda-like” syntax to define the operations (i.e. opcode a b c ...).

Let’s get into it.

I first defined how an operation should be:

1
2
3
4
pub struct Operation {
    pub op: String,
    pub args: Vec<String>,
}

In this way I can parse the input string and get the operation and the arguments like:

1
2
3
4
let mut input = String::new();
std::io::stdin().read_line(&mut input).unwrap();

let operation = parse_operation(input.trim());

The parse_operation function is defined as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
match operation.op.as_str() {
        // We can use the `as_str` method to convert the `String` to a `&str`
        "add" => operation
            .args
            .iter()
            .map(|s| s.parse::<i32>().unwrap())
            .sum(),
        "sub" => {
            let mut args = operation.args.iter().map(|s| s.parse::<i32>().unwrap());
            let first = args.next().unwrap();
            args.fold(first, |acc, x| acc - x)
        }
        "mul" => operation
            .args
            .iter()
            .map(|s| s.parse::<i32>().unwrap())
            .product(),
        "div" => {
            let mut args = operation.args.iter().map(|s| s.parse::<i32>().unwrap());
            let first = args.next().unwrap();
            args.fold(first, |acc, x| acc / x)
        }
        _ => panic!("Unknown operation: {}", operation.op),
    }

Let’s break it down: First, we look for the operation, and then we apply the operation to the arguments. We use the iter method to get an iterator over the arguments, and then we use the map method to convert the &str to i32.

We then apply the operation using the sum, product, fold methods.

Testing

I also implemented some tests to make sure that the operations are working as expected:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_operations() {
        println!("Testing add operation...");
        let operation = parse_operation("add 1 2 3");
        assert_eq!(perform_calculation(operation), 6);
        println!("done.");

        println!("Testing sub operation");
        let operation = parse_operation("sub 10 2 3");
        assert_eq!(perform_calculation(operation), 5);
        println!("done.");

        println!("Testing mul operation");
        let operation = parse_operation("mul 2 3 4");
        assert_eq!(perform_calculation(operation), 24);
        println!("done.");

        println!("Testing div operation");
        let operation = parse_operation("div 10 2 2");
        assert_eq!(perform_calculation(operation), 2);
        println!("done.");
    }
}

This is a simple way to test the operations. We can run the tests using cargo test.

Conclusion

This was a great way to get started with Rust. I learned how to define a struct, how to parse input, and how to write tests. I’m looking forward to the next episode!

As always, thanks for reading! 🚀

Onto the next one! 👋

Federico

This post is licensed under CC BY 4.0 by the author.