Skip to Content
Course content

2: Anatomy of a Rust Program

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Now that you've got your environment humming, we need to look at how a Rust program is actually put together. It's not just about where the code goes, but how Rust expects the "skeleton" of your application to look. To do this, we're going to build a simple Fuel Efficiency Calculator. It's small, but it forces us to deal with the entry point, helper functions, and imports.

Setting up the front door

Every executable Rust program needs a starting point. In Rust, that's the main function. I like to think of it as the front door of your house; no matter how many rooms (functions) you have inside, the guest always enters here. Let's start by declaring our main function and a simple variable.

fn main() {
    let miles = 300.0;
    let gallons = 12.0;
    
    println!("Calculating fuel efficiency...");
}

Note that fn is the keyword we use to define a function. I've used floating-point numbers here (300.0) because fuel efficiency is rarely a clean integer. Rust is very strict about types, so keeping those decimals explicit helps the compiler understand we're dealing with floats right from the start.

Breaking logic into a helper function

You could do all the math right inside main, but that's a bad habit. As your programs grow, main should act more like a conductor and less like the whole orchestra. I want a separate function that handles the actual calculation. This is where we see the anatomy of a function signature: the name, the parameters, and the return type.

fn main() {
    let miles = 300.0;
    let gallons = 12.0;
    
    let mpg = calculate_mpg(miles, gallons);
    println!("Your fuel efficiency is {} MPG", mpg);
}

fn calculate_mpg(distance: f64, fuel: f64) -> f64 {
    distance / fuel
}

Look at calculate_mpg. The -> f64 tells Rust, "This function will hand back a 64-bit float." If I left that out, Rust would assume the function returns nothing (called a "unit type").

Wait, why is my function returning nothing?

Here is where I usually trip up when I'm writing Rust quickly. I'm going to make a mistake that almost every beginner (and many pros) makes: adding a semicolon where it doesn't belong.

fn calculate_mpg(distance: f64, fuel: f64) -> f64 {
    distance / fuel; // I added a semicolon here by habit!
}

If I try to compile this, the compiler will scream at me. Why? Because in Rust, the last expression in a function is the return value if it doesn't have a semicolon. By adding that semicolon, I turned the expression into a statement. A statement doesn't return a value; it just completes. I've effectively told Rust, "Calculate this, then throw the result away and return nothing," which contradicts my -> f64 signature.

The fix is simple: remove the semicolon. It feels weird at first—like you're forgetting something—but it's one of those "Rust-isms" you'll grow to love because it makes the code cleaner.

Pulling in tools from the standard library

Finally, let's make this a bit more robust. What if the user enters 0 for gallons? We'll get an infinity result or a crash. I want to use a tool from the standard library to handle some basic logic. While our example is simple, this is where the use keyword comes in. It's how we bring external modules into scope so we don't have to type the full path every time.

use std::cmp::Ordering;

fn main() {
    let miles = 300.0;
    let gallons = 12.0;
    let mpg = calculate_mpg(miles, gallons);

    // Let's compare this to a "gold standard" of 25 MPG
    match mpg.partial_cmp(&25.0).unwrap() {
        Ordering::Greater => println!("Great efficiency!"),
        Ordering::Less => println!("Could be better."),
        Ordering::Equal => println!("Exactly average."),
    }
}

fn calculate_mpg(distance: f64, fuel: f64) -> f64 {
    distance / fuel
}

By adding use std::cmp::Ordering; at the very top, I can use Ordering::Greater instead of typing std::cmp::Ordering::Greater everywhere. This structure—imports at the top, the entry point in the middle, and helper functions at the bottom—is the standard anatomy of a professional Rust file.




📋 Practical Task

Build a Custom Temperature Converter

Your task is to create a Rust program that converts Fahrenheit to Celsius. To do this, you must follow the structural "anatomy" we discussed in the lesson:

  • Create a main function that serves as the entry point.
  • Create a separate helper function named fahrenheit_to_celsius that takes an f64 and returns an f64.
  • Inside main, define a temperature variable, call your helper function, and print the result.
  • Challenge: Ensure your helper function returns the value using an expression (no return keyword and no trailing semicolon on the final line).

Formula: (Fahrenheit - 32) * 5/9

Rating
0 0

There are no comments for now.

to be the first to leave a comment.