A Basic Introduction to Rust
A Basic Introduction to Rust
While there is no alternative to reading The Book, I'd like to show a bit of the syntax and basics of Rust here.
Here is a Hello World program in Rust:
fn main() {
println!("Hello, world!");
}
The reason it's println!
and not println
is because it's a macro, but macros are far too advanced to be covered here. Rust macros allow you to write code that writes code.
You can print formatted strings, for example:
fn main() {
println!("Hello, {num}", num=5);
}
This will print Hello, 5
.
Variables
Variables are declared using let
, e.g. let x = 5;
. However, don't be fooled! This is not a dynamically typed language, but the type is inferred. That means that Rust understood x should be an integer.
Normal rust variables defined with let
are immutable (you can't do let x = 5; x = 6;
). To make them mutable, use let mut x = 5;
.
Here's a list of common types in Rust:
- Signed integers (can be negative) -
i8
,i16
,i32
,i64
. - Unsigned integers (can't be negative) -
u8
,u16
,u32
,u64
. - Floating point -
f32
,f64
. char
- A unicode character.String
- A string.&str
is a string slice, which is used for efficiency in code.bool
, which istrue
andfalse
.()
, which is the empty type. It's used a lot.- Arrays:
[1, 2, 3]
. Their length can't be changed. - Tuples:
(1, true, "hi")
. Their length can't be changed. Their types are written like(i32, bool, &str)
. - Vector: A variable size array.
vec![1, 2, 3]
orVec::new()
.
Getting input
This is overcomplicated in Rust for some reason, though it's similar to how it is in Java.
use std::io;
fn main() {
let mut input = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
}
Let's explain this. The first line, use std::io
, is similar to how it works in Java: while you could have written std::io::stdin()
, this gives you a shortcut for the rest of your code..read_line(&mut guess)
- giving a function &mut
gives it a mutable reference, so it can change your variables..expect("Failed to read line")
- basic Rust error handling, which prints "Failed to read line" and stops the program.
Conditionals, loops, and such
if
Here is an example of an if expression (I'll explain that later):
let password = "hi";
if password == "CorrectHorseBatteryStaple" {
println!("Correct password!");
} else if password == "123" {
println!("It's not that easy!");
} else {
println!("Incorrect password!");
}
In Rust, if you don't put a semicolon on the last line, the value is returned. You can also use the usual return
. Here is an example of an if expression returning a value:
let b = true;
let x = if b {
5
} else {
7
}
// x is 5
while
// prints 1 ... 99
let mut n = 0;
while n < 100 {
n += 1;
println!("{}", n);
}
loop
Loop is like while true
.
// prints 1 ... 99
let mut n = 0;
loop {
if n >= 100 {
break;
}
n += 1;
println!("{}", n);
}
for
For loops are very similar to Python - they only go over iterators. 0..100
is an iterator of all the numbers 0,...,99. It's similar to range(100)
.
// prints 1 ... 99
for n in 1..100 {
println!("{}", n);
}
You can also iterate over an array or a vector:
// prints 1 2 3
let arr = [1, 2, 3];
for n in arr.iter() {
println!("{}", n);
}
Functions
Here is an example of a function:
fn add(a: i32, b: i32) -> i32 {
a + b
}
fn multiply(a: i32, b: i32) -> i32 {
return a * b;
}
fn printInt(a: i32) -> () {
println!("{}", a);
}
Structs
Probably the most important feature of Rust, this is what replaces Object Oriented Programming. Let's see an example:
struct Point {
x: f64,
y: f64
}
This is a struct with two variables, x and y. Let's put an instance of it in a variable:
let p = Point { x: 3.0, y: 4.0 };
Now, let's add some functions to it:
impl Point {
fn new(x: f64, y: f64) -> Point {
Point { x: x, y: y }
}
fn length(&self) -> f64 {
(self.x * self.x + self.y * self.y).sqrt()
}
}
A function that doesnt take &self
is static and doesn't have access to self. We can call them like this:
let p = Point::new(3.0, 4.0);
println!("{}", p.length); // prints 5
Enums
Enums allow us to make types which can store values of many different types, or just be used as flags.
This will be more obvious with an example:
enum MouseEvent {
LeftClick,
RightClick,
Move(Point),
Scroll(f64)
}
fn show(event: MouseEvent) {
match event {
MouseEvent::LeftClick => {
println!("Left click");
},
MouseEvent::RightClick => println!("Right click"),
MouseEvent::Move(p) => println!("Move to {x}, {y}", x=p.x, y=p.y),
MouseEvent::Scroll(y) => println!("Scroll {}", y)
}
}
fn main() {
show(MouseEvent::LeftClick);
show(MouseEvent::RightClick);
show(MouseEvent::Move(Point::new(3.0, 4.0)));
show(MouseEvent::Scroll(5.3));
}
There's much more to Rust than this, including:
- Ownership.
- Ownership!!!
- Splitting code to multiple files (modules)
- Cargo (using third party packages).
- Traits.
- Error handling.
- Concurrency.
I recommend reading the official book, The Rust Programming Language. It might be a bit of a difficult read, but it's the only way to really know Rust.
nice work!!!
Dude, this is pretty awesome!
It's correcthorsebatterystaple
I think, the capitalization removes entropy.
wow nice
Oh that nice! 😊
How about
&mut input
, and introducing std::Option, and how Rust takes the route of returning errors, more like Haskell, instead of say, C++?Missed a method call here:
Otherwise it seems okay.