Lesson Details

Creating a new Rust Project

To kickstart a new Rust project, we’ll use cargo new with either the --bin or --lib flags, which indicate whether the project will be a binary that can be executed or a library that will be included in another project. The name of our package will be quickstart, which will create a quickstart directory to hold our project.

cargo new quickstart --bin

cargo new creates two files:

  • Cargo.toml
  • main.rs

The file layout is as such, with Cargo.toml at the root of the directory and main.rs in the src directory.

.
├── Cargo.toml
└── src
└── main.rs

Cargo.toml

The Cargo.toml is the package manifest, which contains details like the name and version of the package, the Edition of Rust used, as well as any dependencies.

[package]
name = "quickstart"
version = "0.1.0"
edition = "2024"

[dependencies]

src/main.rs

main.rs is the default entrypoint for a binary crate.

A Rust package can contain multiple binary entrypoints. Often these extra binaries are in a different location like src/bin/ which uses the filename as the binary name by default.

src/main.rs is where the code that will execute when we cargo run lives. This must have a main function, which will execute when our binary does.

fn main() {
println!("Hello, world!");
}

In this case we use a macro, println!, to print "Hello, world!" out to the console. We know println! is a macro because of the !.

We can run the program with cargo run.

❯ cargo run
Compiling quickstart v0.1.0 (/quickstart)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s
Running `target/debug/quickstart`
Hello, world!

Some notable information in the output here is that we built with the dev profile, which is unoptimized and includes debuginfo. By default, Rust programs compile with the dev profile; To enable a release build with optimizations, use the --release flag.

❯ cargo run --release
Compiling quickstart v0.1.0 (/quickstart)
Finished `release` profile [optimized] target(s) in 0.08s
Running `target/release/quickstart`
Hello, world!

The output now notes that we built with the release profile, and is optimized.

cargo run combines cargo check with cargo build, then runs the built binary, which means when we cargo run we also get the built binary in our target directory. The binary for our quickstart program gets built at either target/debug/quickstart or target/release/quickstart, depending on which profile it was built with.

Once built, the binary can be executed directly.

❯ ./target/release/quickstart
Hello, world!

Often the difference in execution speed between the dev profile and the release profile is significant. Consider this program which repeatedly sets the value of result in a loop. Running this program in dev with cargo run takes significantly longer than running in release with cargo run --release.

fn main() {
let mut result = 0;
for i in 0..u32::MAX {
result = i;
}
println!("{result}");
}

Rust is an Expression Based Language

fn main() {
let result = if false { 1 } else { 5 };
dbg!(result);
}

Rust is primarily an expression-based language. This shows up in examples like the one above, where the if expression returns either 1 or 5 based on whether its test is true or false.

Expressions can produce a value, and will return the last value produced in their scope.

For example, we could write a block expression that defines a variable, and then uses it to do some math, then returns the value. This pattern can be used to encapsulate complex data initialization, without leaking intermediate variables into the rest of the code.

fn main() {
let result = {
let a = 5;
5 * a
};
dbg!(result);
}