Before we begin, I highly recommend you to give a read to my previous article in this series.
Let me give you a short recap of what we achieved in the previous article.
- How to make a new directory for your project using Cargo.
- What is Cargo
- What are dependencies in Rust and how to use one
- What’s
Cargo.toml
- How to import modules
- Mutable and Immutable variables in Rust
-
String
in Rust. - How to flush output without using
\n
orprintln!
- How to take input from user and store it in a variable
With that done, lets jump back to our code.
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");
let a: f32 = a.trim().parse().unwrap();
let b: f32 = b.trim().parse().unwrap();
let operator: char = operator.trim().chars().next().unwrap();
}
We changed the type of our variables a
and b
as float type, and the type which takes up 32 bits or 4 bytes in memory. Then we removed any white spaces using .trim()
, parsed our String
type variable to f32
type variable using .parse()
and .unwrap()
returns our value if there is one, or it will panic (stop the execution), if there isn’t.
Speaking of the variable operator
, we changed its type to char
, removed any whitespaces using .trim()
, converted the String
type to char
type using .chars()
, and advanced the iterator over the string using .next()
until it returned None
, which means we iterated over the string until each character of the string is char
type with the help of .next()
.
Since we are making a simple calculator, we want to limit our operations to:
- Addition
- Subtraction
- Multiplication
- Division
Let’s make a separate String
for that, which contains the operators for all the above mentioned four operations.
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");
let a: f32 = a.trim().parse().unwrap();
let b: f32 = b.trim().parse().unwrap();
let operator: char = operator.trim().chars().next().unwrap();
let operators = String::from("+-/*");
}
Notice that we use String::from
instead of String::new
. It’s because we want to make operators
of type String
which contains the string "+-/*"
.
We want to make sure that the user inputs only these 4 operators, not any other. For that, we add :
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");
let a: f32 = a.trim().parse().unwrap();
let b: f32 = b.trim().parse().unwrap();
let operator: char = operator.trim().chars().next().unwrap();
let operators = String::from("+-/*");
if !operators.contains(operator){
panic!("Invalid operator");
}
}
This checks whether the string operators
contains the character stored by the variable operator
. If it doesn’t, the execution stops, and the message “Invalid operator”
is displayed.
Now let’s move on to the “operating on the numbers” part.
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");
let a: f32 = a.trim().parse().unwrap();
let b: f32 = b.trim().parse().unwrap();
let operator: char = operator.trim().chars().next().unwrap();
let operators = String::from("+-/*");
if !operators.contains(operator){
panic!("Invalid operator");
}
let mut result: f32 = 1.0;
if operator =='+'{
result = a + b
}
else if operator == '-' {
result = a - b
}
else if operator == '*' {
result = a * b
}
else if operator == '/'{
result = a / b
}
}
We need a variable to store the result of our operation on the numbers, hence the variable result
.
We also need to initialize the variable, otherwise while printing the value of result
, we would be facing an error from compiler.
If you are reading this article, chances are that you know what if
,else
and else if
are.
We compare our variable operator
with different operator signs, and if the condition evaluates to true, the if
or else if
block is executed.
Notice that we are not using semicolons when inside the if
or else if
block. That’s because we want to return the value of expression to our variable result.
Let me explain. Rust is primarily an expression language. An expression can be a line or piece of code which returns a value.
Then there are statements, which is a piece or line of code that executes and tells the computer to do something specific.
Examples for statement are :
use std::io::{stdin, stdout, Write};
and
print!("Enter number : ");
An expression which evaluates to a value would look like :
if operator =='+'{
result = a + b
}
Here, the value of a + b
is returned to the variable result
.
Let’s consider an example to understand this concept much better.
let mut a = {
let b = 10;
b*b
};
After executing the above code, the value of variable a
would be 100.
But if we execute the code below :
let mut a = {
let b = 10;
b*b;
};
Then printing a
would give us ()
, as it contains no value.
An important line is still missing from our code. We need to print the result of our calculation.
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");
let a: f32 = a.trim().parse().unwrap();
let b: f32 = b.trim().parse().unwrap();
let operator: char = operator.trim().chars().next().unwrap();
let operators = String::from("+-/*");
if !operators.contains(operator){
panic!("Invalid operator");
}
let mut result: f32 = 1.0;
if operator =='+'{
result = a + b
}
else if operator == '-' {
result = a - b
}
else if operator == '*' {
result = a * b
}
else if operator == '/'{
result = a / b
}
println!("Result of {} {} {} is : {}", a, operator, b, result)
}
There. Now our code is complete. The curly braces would take up the value of the variables mentioned after the string. It is important to keep in mind that we need to keep the order of variables correct. println!
prints to the standard output, but with a newline.
We are now done with the coding part!
Now, we need to run our code.
For that, we need to run the following command :
cargo run
This command builds and runs our project. It creates the executable file target/debug/rust-calc
or target/debug/rust-calc.exe
on Windows.
To run our project in an Enarx keep, we need to create a .wasm
file of our project. But first, make sure that you installed the WebAssembly Rust toolchain. The command to install the same is :
rustup target install wasm32-wasi
To generate the .wasm
file of our project, run the following command.
cargo build --release --target=wasm32-wasi
But why are we generating a .wasm file for our Rust code?
To run it in an Enarx keep. Enarx provides a WebAssembly runtime, based on wasmtime.
We can find our .wasm
file in target/wasm32-wasi/release/rust-calc.wasm
.
Finally, we can run our project in an Enarx keep with this simple command.
enarx run target/wasm32-wasi/release/rust-calc.wasm
To recap briefly, you now know :
- How to change the type of a variable
- What does
.trim()
,.parse()
,.next()
,.unwrap()
do - How to use
panic!
- How to use
.contains()
on a string - How to use
if
,else if
andelse
in Rust. - Difference between an expression and a statement
- When to use and not to use semicolon in Rust.
- How to use
println!
in Rust. - How to build and run a project using
cargo
. - How to generate a
.wasm
of our project. - How to run a
.wasm
file in an Enarx keep.
Congratulations 🥳 !
You just went from a complete newbie in Rust to making a calculator in Rust and running it in an Enarx keep!
This is just the beginning. I highly suggest you to read “The Rust programming Language” book, which can found here, to get familiar and learn more concepts of Rust.
With this, I come to the end of this series. I hope you enjoyed this as much as I did.
Never stop learning and exploring 😃
I will see you in the next one.
Top comments (8)
You're on the right path, keep exploring stuff and publishing it. Don't get discouraged by trolls like timq.
When learning new languages, try to adapt to the way things are done on that language, the Rust Way, in this case.
Making posts like this and explaining things you learned are very helpful to you, they give better clarity for what you learned and will expose the things you thought you knew but need better understanding, that is basically the feynman learning technique.
Thank you for your kind and encouraging words William!
This is by far one of the worst introductions to the Rust language I've ever seen.
Thanks for your feedback. May I request you to please let me have your views/gripes, which you think are not accurate and are far from factual.
This will help me better understand your perspective and hopefully resolve and improve further :)
Thanks again for your constructive and positive feedback for a student/intern.
This article is for those, who do not know anything about Rust and have no experience, and the big part of the target audience is students.
We learn from experiences and in the process grow to achieve a higher credibility.
Thanks again and best wishes
This literally ruins the Rust experience for many. They'll only know shit about Rust from now on.
timq, you're probably not as good a programmer as you think you are if you need to be this rude to people just to feel better about yourself.
Moksh is still studying, learning a new language and is already publishing stuff, this is just a learning project, it doesn't have to be perfect, it's just one of many projects he'll do while learning Rust. You act like you were never at this stage, like you never did bad code.
You tried to look good here, but just made a fool of yourself:
When you said "This is by far one of the worst introductions to the Rust language I've ever seen.": Moksh wasn't introducing Rust to readers, as the tittle makes pretty clear: "How I made a calculator..." he was just showing his project and explaining what he learned building it.
Then you made a few, simple and badly explained, suggestions about things that Moksh will probably learn by himself in his next projects. But you didn't miss the opportunity to be rude again.
And then: "This literally ruins the Rust experience for many. They'll only know shit about Rust from now on." Seriously? Like anyone learning Rust would use just these posts for studying the language.
I think comments like yours timq are ruining the Rust/Whatever experience for everyone. Be helpful or just shut up.