Getting Started with Rust:
Installation and First Steps

Last updated: April 13, 2025

1. Introduction: Why Rust?

Rust is a modern systems programming language focused on three primary goals: safety, speed, and concurrency. It achieves memory safety (preventing common bugs like null pointer dereferencing, buffer overflows, and data races) without needing a garbage collector, primarily through its innovative ownership and borrowing system.

This makes Rust suitable for a wide range of applications, from low-level embedded systems and operating systems to high-performance web servers, command-line tools, and even game development. Its strong type system and compile-time checks catch many errors before they reach production.

This guide will walk you through installing Rust, writing your first program, and understanding the basics of its syntax and tooling.

2. Installation with rustup

The official and recommended way to install Rust is using rustup, the Rust toolchain installer. It manages Rust versions and associated tools like cargo (the build tool and package manager) and rustc (the compiler).

Visit the official Rust installation page at rust-lang.org and follow the instructions for your operating system. Typically, this involves running a single command in your terminal:

# Example for Linux/macOS (check official site for current command)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

The installer will guide you through the process. After installation, ensure your shell environment is configured (you might need to restart your terminal or run source $HOME/.cargo/env). Verify the installation:

rustc --version
cargo --version

rustup also makes updating easy:

rustup update

3. Your First Rust Program: Hello, World!

Let's create the classic "Hello, world!" program.

3.1 Writing the Code

  1. Create a new directory for your project, e.g., mkdir ~/projects/hello_rust && cd ~/projects/hello_rust.
  2. Create a file named main.rs (Rust source files use the .rs extension).
  3. Open main.rs in your text editor and add the following code:
// main.rs

// The main function is the entry point of every executable Rust program.
fn main() {
    // println! is a macro that prints text to the console.
    println!("Hello, world!");
}
  • fn main() { ... } defines the main function.
  • println! is a Rust macro (indicated by the !). Macros are a way of writing code that writes other code (metaprogramming). println! prints the provided string to the standard output, followed by a newline.

3.2 Compiling and Running

  1. Compile the code using the Rust compiler, rustc:
    rustc main.rs
    This creates an executable file (named main on Linux/macOS, main.exe on Windows).
  2. Run the executable:
    # On Linux/macOS
    ./main
    
    # On Windows (Command Prompt)
    .\main.exe
    
    # On Windows (PowerShell)
    .\main

You should see the output: Hello, world!

4. Introduction to Cargo: Rust's Build Tool & Package Manager

While rustc is fine for simple programs, most Rust projects use Cargo. Cargo handles building code, downloading libraries (called "crates" in Rust), managing dependencies, running tests, and more.

4.1 Creating a Cargo Project

Let's recreate "Hello, world!" using Cargo:

  1. Navigate to your projects directory (e.g., cd ~/projects).
  2. Create a new project using Cargo:
    cargo new hello_cargo
  3. This command creates a new directory called hello_cargo with the following structure:
    hello_cargo/
    ├── Cargo.toml
    └── src/
        └── main.rs
    • Cargo.toml: The configuration file for your project (metadata, dependencies). This is called the *manifest*.
    • src/main.rs: The source code file, pre-populated with the "Hello, world!" code.

Open Cargo.toml. It will look something like this:

[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021" # Rust edition (controls language features)

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

[dependencies]
# Crates (libraries) your project depends on go here

4.2 Building and Running with Cargo

  1. Navigate into the new project directory: cd hello_cargo.
  2. Build the project:
    cargo build
    This compiles your code and places the executable in target/debug/hello_cargo. The first build might be slower as Cargo sets things up. Subsequent builds are faster.
  3. Run the project:
    cargo run
    This command compiles the code (if necessary) and then runs the resulting executable. You should see Hello, world! again.
  4. Check the project for correctness without producing an executable:
    cargo check
    This is much faster than `cargo build` and useful for quickly verifying code during development.
  5. Build an optimized release version:
    cargo build --release
    This creates an optimized executable in target/release/hello_cargo.

Cargo significantly simplifies the build and run process compared to using rustc directly.

4.3 Adding Dependencies

Cargo makes it easy to use libraries (crates) from the community registry, crates.io. To add a dependency (e.g., the popular rand crate for random number generation), edit your Cargo.toml:

[dependencies]
rand = "0.8" # Add the crate name and desired version

The next time you run cargo build or cargo run, Cargo will automatically download and compile the rand crate and its dependencies.

Alternatively, use the command line:

cargo add rand

5. Basic Rust Syntax Overview

Here's a glimpse of some fundamental Rust syntax elements:

5.1 Variables and Mutability

Variables are immutable by default. Use the mut keyword to make them mutable.

let x = 5; // Immutable variable
let mut y = 10; // Mutable variable

// x = 6; // Error: cannot assign twice to immutable variable `x`
y = 11; // OK: `y` is mutable

5.2 Common Data Types

Rust is statically typed, meaning the compiler must know the type of every variable at compile time. It has type inference, but you can add type annotations.

  • Integers: Signed (i8, i16, i32, i64, i128, isize) and Unsigned (u8, u16, u32, u64, u128, usize). Example: let count: i32 = 100;
  • Floating-Point: f32, f64. Example: let price: f64 = 99.99;
  • Boolean: bool (values true or false). Example: let is_active: bool = true;
  • Character: char (single Unicode scalar value, uses single quotes). Example: let initial: char = 'A';
  • Tuples: Fixed-size collection of potentially different types. Example: let tup: (i32, f64, char) = (500, 6.4, 'z');
  • Arrays: Fixed-size collection of the same type. Example: let numbers: [i32; 5] = [1, 2, 3, 4, 5];
  • Strings: The primary string type is String (heap-allocated, growable) and string slices &str (a view into string data, often string literals).

5.3 Functions

Defined using the fn keyword. Type annotations for parameters and the return value are required.

fn add(x: i32, y: i32) -> i32 {
    // The last expression in a function is implicitly returned (no semicolon)
    x + y
    // Or explicitly return using the `return` keyword:
    // return x + y;
}

fn main() {
    let sum = add(5, 7);
    println!("Sum is: {}", sum); // Output: Sum is: 12
}

5.4 Comments

// This is a single-line comment.

/*
 * This is a
 * multi-line block comment.
 */

/// This is a documentation comment for the following item.
fn documented_function() {}

//! This is a documentation comment for the enclosing item (e.g., the module or crate).

5.5 Control Flow (if/else, loops)

let number = 6;

// if/else expressions
if number % 4 == 0 {
    println!("number is divisible by 4");
} else if number % 3 == 0 {
    println!("number is divisible by 3");
} else {
    println!("number is not divisible by 4 or 3");
}

// loop (infinite loop, break to exit)
let mut counter = 0;
loop {
    println!("Again!");
    counter += 1;
    if counter == 3 {
        break; // Exit the loop
    }
}

// while loop
let mut n = 3;
while n != 0 {
    println!("{}!", n);
    n -= 1;
}
println!("LIFTOFF!!!");

// for loop (iterating over a collection)
let a = [10, 20, 30, 40, 50];
for element in a {
    println!("the value is: {}", element);
}

// for loop with a range
for num in (1..4).rev() { // 3, 2, 1 (rev() reverses range)
    println!("{}!", num);
}

6. Next Steps

This guide covers the very basics. Key concepts to explore next in Rust include:

  • Ownership and Borrowing: Rust's core memory management system.
  • Structs and Enums: Defining custom data structures.
  • Error Handling: Using Result and panic!.
  • Collections: Vectors (Vec), Hash Maps (HashMap), etc.
  • Traits: Rust's approach to shared behavior (similar to interfaces).
  • Concurrency: Threads, message passing, async/await.

7. Additional Resources

Related Articles

External Resources