Rust-03: Improving the simple program
Tags: rust, programming
Published: 2022-11-08 11:00:00

In the last post we created a simple program that would accept an input like `5+5` and calculates the result.
In this post we will improve this program.

To prepare for adding more operators we need to improve the input-parsing.
Currently, we just split the input-string at the plus-sign.
If we want to know the operator, we have to choose another approach.

In this case I chose regex:
```rust
#[derive(Debug)]
struct Operation {
    left: i32,
    operator: char,
    right: i32,
}

impl Operation {
    fn from_string(input: &String) -> Option<Operation> {
        let regex = Regex::new(r"^\s*(\d+)\s*([+])\s*(\d+)\s*$").unwrap();

        regex.captures(&input).map(|capture| Operation {
            left: (&capture[1]).parse().unwrap(),
            operator: (&capture[2]).parse().unwrap(),
            right: (&capture[3]).parse().unwrap(),
        })
    }
}
```

As you can see we have a new thing called `struct` in the code.
If you are coming from a language like Java or Typescript, a struct can be seen as a class without any methods.
This struct is called `Operation` and as the name suggests it holds an operation.
The fields `left` and `right` are both typed as an `i32` or in other words a "signed 32-bit integer".
The field `operator` is a `char` since we only use one character for an operator.
In rust `strings` and `chars` are utf-8, therefore a `char` can contain one unicode codepoint, not just a byte.

The other new thing is a `impl` called `Operation`.
An `impl` is the method-part equivalent of a class.
Here you can define methods, that are available to call on the struct with the same name.
In this case we have one method called `from_string`.
This method is our new parser.
It takes a string as an input and returns an `Operation` wrapped by an `Option`.
Rust does not have `null`, so every time when there is the possibility that a value could be non-existent an `Option` is used.

If you read the code carefully, you may have noticed that the last statement of the function does not have a semicolon.
That is on purpose.
If the last statement of a function has a semicolon, it returns `()` (equivalent to `void`), if it isn't preceded by the keyword `return`.
You can omit the keyword `return` by omitting the semicolon on the last statement of a function.
Then, the value of the last statement is used as the return value.


Now we have a new method of parsing, so lets look at the new evaluator:

```rust
let operation = Operation::from_string(&input).expect("Your input is invalid");

let result = match operation {
    Operation { left, operator: '+', right } => Ok(left + right),
    x => Err(format!("{} is not a valid operator", x.operator)),
};


println!("The result is: {:?}", result.unwrap());
```

Here we can see another example of a powerful feature of Rust: Pattern matching.
With pattern matching, we can save a lot of else-if-statements.
In this simple case it wouldn't make a big difference, but we want to expand the code.

So what happens inside the `match operation {...` statement?
Each line contains a Pattern, followed by `=>` and a statement or block.
The pattern `Operation { left, operator: '+', right }` matches every `Operation` with `+` as its operator.
`left` and `right` have no value assigned in the pattern, so all values match.
You can use `left` and `right` as variables in your following statement, as seen in the code.
`x => ...` matches all cases, it's therefore the `default` case.


After these changes, we are at state: [24affc71](https://github.com/nidomiro/learning-rust-calculator/tree/24affc713401046fd0c81c11c5beb1e9fe991c6c)

In the next post we will add more operators to the calculator and more.