
Your First Rust App: A Step-by-Step Guide
Welcome to the world of Rust! This is an opinionated, hands-on guide designed for complete beginners. Forget the theory for a moment—we’re going to get you from zero to a small, functional command-line app and introduce you to key concepts along the way.
Ready? Let’s dive in.
1. Install Rust
The best way to install Rust is with rustup, the official toolchain manager. It’s the simplest and most reliable method for keeping your installation up-to-date.
- macOS / Linux: Open your terminal and run the following commands:Bash
curl https://sh.rustup.rs -sSf | sh source $HOME/.cargo/env
- Windows: Download and run
rustup-init.exe
from the official Rust website. Accept the default installation options.
After the installation is complete, open a new terminal (or Command Prompt/PowerShell on Windows) and verify everything is working by running:
Bash
rustc --version
cargo --version
You should see version numbers for both rustc
(the Rust compiler) and Cargo (Rust’s build tool and package manager).
2. Create and Run Your First Project
Cargo is a cornerstone of the Rust ecosystem. It handles everything from creating new projects to building, testing, and managing dependencies. Let’s use it to get started.
Bash
cargo new hello-rust
cd hello-rust
This command scaffolds a new binary application called hello-rust
. You now have a clean project structure:
hello-rust/
├─ Cargo.toml # Project metadata & dependencies
└─ src/
└─ main.rs # The entry point for your application
To run the default “Hello, world!” program, use the cargo run
command.
Bash
cargo run
The first run will take a moment as Cargo compiles your code and its dependencies. On subsequent runs, it will be lightning fast. You should see:
Hello, world!
3. Make It Interactive
Now let’s replace the default program with something more useful. Open src/main.rs
in your favorite code editor and replace its contents with the following code.
Rust
use std::io::{self, Write};
fn main() {
print!("What is your name? ");
io::stdout().flush().unwrap();
let mut name = String::new();
io::stdin().read_line(&mut name).expect("Failed to read input");
let name = name.trim();
println!("Hi, {name}! Welcome to Rust 🚀");
}
This code does a few things:
use std::io...
brings the standard I/O library into scope.let mut name...
declares a mutable variable. In Rust, variables are immutable by default, which is a powerful safety feature.io::stdin().read_line...
reads a line from the user’s input.println!
is a macro (note the!
) that prints formatted text to the console.
Run the new program with cargo run
and see what happens!
4. Add Real Logic: A Temperature Converter
Reading a user’s name is cool, but let’s do something more complex. Replace the code in src/main.rs
with this simple temperature converter that converts Celsius to Fahrenheit.
Rust
use std::io::{self, Write};
fn main() {
print!("Enter temperature in °C: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).expect("read failed");
let celsius: f64 = match input.trim().parse() {
Ok(v) => v,
Err(_) => {
eprintln!("Please enter a valid number, e.g., 36.6");
return;
}
};
let fahrenheit = c_to_f(celsius);
println!("{celsius}°C is {fahrenheit}°F");
}
fn c_to_f(c: f64) -> f64 {
(c * 9.0 / 5.0) + 32.0
}
This example introduces some key Rust concepts:
match
is a powerful construct for handling different outcomes, similar to aswitch
statement but more expressive.- The
parse()
method on a string returns aResult
type, which can be either anOk(value)
or anErr(error)
. This is Rust’s preferred way of handling fallible operations instead of throwing exceptions. fn c_to_f(...) -> f64
defines a function that takes a floating-point number (f64
) as input and returns one.
Now run cargo run
and test it out!
5. Add a Dependency and Write a Test
The Rust ecosystem is built on crates (libraries) published to crates.io
. To use a crate, you simply add it to your Cargo.toml
file.
Open Cargo.toml
and add the rand
crate under the [dependencies]
section.
Ini, TOML
[dependencies]
rand = "0.8"
Now, replace the code in src/main.rs
with this simple number-guessing game.
Rust
use rand::Rng;
fn main() {
let secret = rand::thread_rng().gen_range(1..=10);
println!("I picked a number between 1 and 10: {secret}");
}
When you run cargo run
, Cargo will automatically download and compile the rand
crate for you.
Write a Test
A core part of building reliable software is writing tests. Let’s add a unit test for our temperature conversion function (from step 4) to ensure it works correctly.
Add the following block of code to the bottom of your src/main.rs
file.
Rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn converts_correctly() {
assert_eq!(c_to_f(0.0), 32.0);
}
}
#[cfg(test)]
tells Rust to only compile this code when running tests.mod tests
creates a new module for our tests.#[test]
marks theconverts_correctly
function as a test.assert_eq!
is a macro that panics if the two arguments are not equal.
Run your new test with cargo test
and watch it pass.
6. Build and Ship Your App
When you run cargo build
, it creates a debug version of your executable in target/debug/hello-rust
. For a production-ready application, you want to build an optimized, fast binary.
Bash
cargo build --release
This generates an optimized executable and places it in target/release/hello-rust
. This is the file you would distribute to others.
What’s Next?
Congratulations! You just installed Rust, built and ran a project, handled user input, added logic and a dependency, wrote a test, and built a release binary. That’s a solid first lap.
Here are a few things to explore next:
- Code Organization: Learn how to split your code into modules and different files.
- Error Handling: Dig deeper into Rust’s
Result
andOption
types and how to handle errors gracefully. - Advanced Concepts: Explore structs, enums, slices, and the core concepts of ownership and borrowing.
Ready for your next challenge? Try a tiny REST client or a simple game when you feel ready.
Do you have a specific goal you’d like to achieve with Rust?
