Rust Fundamentals for Beginners
Rust Basics
Setting Up Your Workshop
Before you can write Rust code, you need to set up your tools. The official and easiest way to install Rust is by using rustup, a command-line tool for managing Rust versions and associated tools. Open your terminal and run the following command. It will guide you through the installation process.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Once installed, you'll have the Rust compiler, rustc, and its package manager, cargo. We'll mostly use cargo because it simplifies project management, from creation to compilation.
Let's create our first project. In your terminal, navigate to where you want to store your code and run:
cargo new hello_world
cd hello_world
cargo creates a new directory called hello_world with a src folder inside, containing a main.rs file. This is where your code will live. It also creates a Cargo.toml file, which is a configuration file for your project. Let's look at what's inside main.rs.
fn main() {
println!("Hello, world!");
}
This is the classic starter program. The fn main() part defines the main function, the entry point of every executable Rust program. println! is a macro that prints text to the console. The exclamation mark means you're calling a macro instead of a normal function.
To run this program, use cargo:
cargo run
Cargo will compile and execute your code. You should see Hello, world! printed to your terminal. You've just written and run your first Rust program.
Variables and Data
In Rust, variables are immutable by default. This is a core safety feature. When you declare a variable with the let keyword, you can't change its value later.
fn main() {
let x = 5;
println!("The value of x is: {}", x);
// x = 6; // This would cause a compile error!
println!("The value of x is still: {}", x);
}
If you need a variable you can change, you must explicitly make it mutable using the mut keyword.
fn main() {
let mut y = 10;
println!("The initial value of y is: {}", y);
y = 20;
println!("The new value of y is: {}", y);
}
Constants are similar to immutable variables but have a few key differences. They are always immutable, must have their type annotated, and can be declared in any scope, including the global scope. We use the const keyword.
const SECONDS_IN_MINUTE: u32 = 60;
Rust is a statically typed language, which means it must know the types of all variables at compile time. However, the compiler can usually infer the type based on the value. Every value in Rust has a specific data type. Here are the main primitive types you'll encounter.
| Type | Description |
|---|---|
| Integers | Whole numbers. Can be signed (i8, i32, i64, etc.) or unsigned (u8, u32, u64, etc.). The number indicates the bits it takes up in memory. |
| Floating-Point | Numbers with a decimal point. Two types: f32 (single-precision) and f64 (double-precision). |
| Booleans | The bool type has two possible values: true or false. |
| Characters | The char type represents a single Unicode character. You specify char literals with single quotes. |
Controlling the Flow
Like other languages, Rust lets you control the flow of your code using conditions and loops. The if expression is straightforward. It executes a block of code if a condition is true.
let number = 7;
if number < 10 {
println!("The number is small.");
} else {
println!("The number is large.");
}
You can also use else if to handle multiple conditions.
Rust provides three kinds of loops: loop, while, and for.
A loop will repeat forever until you explicitly tell it to stop with the break keyword.
let mut counter = 0;
loop {
counter += 1;
println!("Again!");
if counter == 5 {
break;
}
}
A while loop runs as long as a condition remains true.
let mut number = 3;
while number != 0 {
println!("{}!", number);
number -= 1;
}
println!("LIFTOFF!!!");
The most common and safest loop in Rust is the for loop. It's used to iterate over a collection, like a range of numbers.
for number in 1..4 {
println!("{}!", number);
}
println!("LIFTOFF!!!");
This example iterates through numbers 1, 2, and 3. The 1..4 creates a range that is inclusive on the left and exclusive on the right.
Building with Functions
Functions are the primary way to organize code in Rust. We've already seen main, the most important function. You can define your own functions using the fn keyword.
fn main() {
println!("Hello from main!");
another_function();
}
fn another_function() {
println!("Hello from another function!");
}
Functions can also take parameters. You must declare the type of each parameter.
fn main() {
print_value(12);
}
fn print_value(x: i32) {
println!("The value is: {}", x);
}
Functions can return values, too. The return type is specified after an arrow ->. The final expression in a function will be used as the return value. Notice the lack of a semicolon; if you add one, it becomes a statement, not an expression, and won't return a value.
fn main() {
let sum = add_two(5, 7);
println!("5 + 7 = {}", sum);
}
fn add_two(a: i32, b: i32) -> i32 {
a + b // No semicolon means this is the return value
}
Time to check your understanding.
What is the primary command-line tool used to install and manage Rust versions and their associated tools?
How do you create a new Rust project named my_app using Cargo?
That's a quick tour of the very basics. You've learned how to set up your environment, write a program, handle variables, use data types, control program flow, and define functions. This is the foundation for everything else you'll do in Rust.