Wasm Builders

Moksh Pathak
Moksh Pathak

Posted on

How I made a calculator in Rust and ran it in an Enarx Keep - Part 1

So you have just begun to explore Rust, and you want to make a simple, easy project to get familiar with the nuances and learn on the go, but you don’t know where to begin with.

If you are learning a new language, it is best to implement a project that you already have in some other language you are comfortable with, and I’m pretty sure that you would have coded a program which did the job of a calculator in some point of your life.

Even if you have no experience in any other language, fret not, I shall try my best to break the code down into simple, bite sized understandable format.

So take a deep breath and lets get going!


First, lets make a new directory for our project.

cargo new rust-calc
Enter fullscreen mode Exit fullscreen mode

Cargo is the package manager of Rust. It handles a lot of tasks for you, such as downloading and building the libraries your code depends on.

By default, using the above command also initializes a git repository.

├── Cargo.toml
├── src
    └── main.rs
└── .gitignore
Enter fullscreen mode Exit fullscreen mode

As you can see, 2 files and 1 directory were generated. src directory has a main.rs file inside.

.toml format (Tom’s Obvious, Minimal Language) is the Cargo’s configuration format.

Your Cargo.toml file would look something like this -

[package]
name = "calc_rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Enter fullscreen mode Exit fullscreen mode

Under the dependencies, we list all the libraries (or dependencies) our project needs.

For this particular project, we don’t need any other dependencies.

Now lets take a look on our src/main.rs .

fn main() {
        println!("Hello, World!");
}
Enter fullscreen mode Exit fullscreen mode

Doesn't look like C?

Did the code snippet above make you reminisce C? Me neither hehe.

Cargo has generated a “Hello, World!” program for you.

We shall be editing this file later on to achieve the goal of our project.


Lets come to the good part, Coding!

Let's Code!

Let’s import the modules responsible for I/O operations

use std::io::stdin;
use std::io::stdout;
use std::io::Write;
Enter fullscreen mode Exit fullscreen mode

Or simply

use std::io::{stdin, stdout, Write};
Enter fullscreen mode Exit fullscreen mode

Like C and C++, fn main() is where the execution of program begins. Lets type it out.

use std::io::{stdin, stdout, Write};

fn main(){

}
Enter fullscreen mode Exit fullscreen mode

Like def in Python, fn is the keyword in Rust to denote functions.

Tip : Rust uses Snake case as the conventional style for function and variable names, in which all letters are lowercase and underscores separate words.

We are making a simple calculator, and we need to store numbers to perform operation on them. We need variables.

By default, all the variables in Rust are immutable. It means we can’t mutate/change their values.

To make the variables mutable, we use the keyword mut.

Let’s make three variables of String type, two for holding numbers and one for holding operator.

use std::io::{stdin, stdout, Write};

fn main(){
    let mut a = String::new();
    let mut b = String::new();
    let mut operator = String::new();
}
Enter fullscreen mode Exit fullscreen mode

There are two types of strings in Rust : String and &str. Former is heap allocated, growable and not null terminated. &str is static in nature.

Printing a message on terminal is quite simple in Rust.

use std::io::{stdin, stdout, Write};

fn main(){
    let mut a = String::new();
    let mut b = String::new();
    let mut operator = String::new();
    print!("Enter number 1 : ");
    stdout().flush().expect("Couldn't flush statement 1");
}
Enter fullscreen mode Exit fullscreen mode

Huh?

It is simple. Seriously. Let me explain.

If we don’t use this line of code

 stdout().flush().expect("Couldn't flush statement 1");
Enter fullscreen mode Exit fullscreen mode

Then “Enter number 1 : “ will be printed on the console after the input from user.

When a new line (\n) is written to stdout , the buffer is flushed.

Since we are not using a new line character, we need to manually tell the OS to flush the output.

If that didn’t make sense, just know that we need to manually tell the OS to print “Enter number 1 : “ so that it doesn’t print it after taking input from the user.

If our attempt to flush fails, a message “Couldn’t flush statement 1” is displayed. Awesome, right?

This can also solved using println!, but that would look like :

Enter number 1 :
5
Enter fullscreen mode Exit fullscreen mode

Whereas, I want it to look like :

Enter number 1 : 5
Enter fullscreen mode Exit fullscreen mode

Now let’s take the input from user.

use std::io::{stdin, stdout, Write};

fn main(){
    let mut a = String::new();
    let mut b = String::new();
    let mut operator = String::new();
    print!("Enter number 1 : ");
    stdout().flush().expect("Couldn't flush statement 1");
    stdin().read_line(&mut a).expect("Couldn't read number 1");
}
Enter fullscreen mode Exit fullscreen mode

stdin().read_line(&mut a).expect("Couldn't read number 1"); reads a line of user input as a String and returns it to our variable a.

If it fails to do that, the program execution stops and the message “Couldn’t read number 1” is displayed.

Now lets quickly take in the other 2 inputs from user.

use std::io::{stdin, stdout, Write};

fn main(){
    let mut a = String::new();
    let mut b = String::new();
    let mut operator = String::new();
    print!("Enter number 1 : ");
    stdout().flush().expect("Couldn't flush statement 1");
    stdin().read_line(&mut a).expect("Couldn't read number 1");
    print!("Enter number 2 : ");
    stdout().flush().expect("Couldn't flush statement 2");
    stdin().read_line(&mut b).expect("Couldn't read number 2");
    print!("Enter the operation (+, -, *, /) : ");
    stdout().flush().expect("Couldn't flush statement 3");
    stdin().read_line(&mut operator).expect("Couldn't read operator");
}
Enter fullscreen mode Exit fullscreen mode

The above code snippet takes three inputs. Two for storing numbers, or the operands, and one for storing the operator. The operands are stored in the variables a and b while the operator is stored in the variable operator.

To recap briefly, you now know

  • How to make a new directory for your project using Cargo.
  • What is Cargo
  • What are dependencies in Rust
  • What’s Cargo.toml
  • How to import modules
  • Mutable and Immutable variables in Rust
  • String in Rust.
  • How to flush output without using \n or println!
  • How to take input from user and store it in a variable

Now you are probably thinking that we are still far away from making a calculator, then why you are giving a recap Moksh?

Two reasons.

To remind you that you have learned and accomplished a lot in the last few minutes, and to learn even more, you need to read my second article in this short series 🙂.

Any suggestions/improvements to make this article even better are more than welcome.

Till then, keep exploring and learning.

Best,

Moksh Pathak

Discussion (2)

Collapse
kirteeprajapati profile image
Kirtee Prajapati

This article actually helped me getting lot of stuff that i was actually not known to Thank you @moksh_pathak for this to the point explaination. 😊

Collapse
moksh_pathak profile image
Moksh Pathak Author

I am glad you found this helpful Kirtee! Thanks for reading!