Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Rust (2024 edition)  Module 1 – Getting started: rustup, Cargo and compiler messages

Why Rust: safety, speed and where it runs

Which bugs safe Rust refuses to compile, which it stops while the program runs and which it lets through, how releases work and where Rust runs.

  • Beginner
  • 15 minutes
  • Examples run with Rust 1.99.0 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Explain which bugs safe Rust refuses to compile, which it stops at run time and which it lets through
  • Identify a toolchain's release and edition, and when the next stable release arrives
  • Describe where Rust is used today, citing the projects' own publications
  • Read a recorded run: its command, its toolchain, what it printed and how it ended
What you’ll learn

What you will learn

  • Explain which bugs safe Rust refuses to compile, which it stops at run time and which it lets through
  • Identify a toolchain's release and edition, and when the next stable release arrives
  • Describe where Rust is used today, citing the projects' own publications
  • Read a recorded run: its command, its toolchain, what it printed and how it ended
On this page

Change two lines of the 14-line bill program on this page, and Rust refuses to build it: error E0382, a list used after it was handed to another function. Run as written, that program would use a list whose memory had already been freed, and the compiler stops it before a program exists.

That refusal is at the heart of what Rust offers, and it costs nothing while a program runs. This lesson shows what safe Rust rules out and what it still lets through, both on recorded runs, then how releases and edition: A set of language rules that each crate chooses in Cargo.toml: 2015, 2018, 2021 or 2024. A new edition changes nothing for crates that keep an older one, and crates of different editions work together. work and where Rust is used, each claim from the organisation that published it. By the end you can read every run in this track: the command, the toolchain, what it printed and how it ended.

Rust refuses to build a program that uses memory it gave away

Here is the program: a canteen bill of three items, kept in paise so that the arithmetic stays exact. total adds up the amounts, and main prints each line, then the number of items and the sum:

bill_total.rs: a bill that builds and runs Rust · bill_total.rs
// A canteen bill kept in paise, whole numbers, so no rounding error can creep in.
fn total(items: &[(&str, u64)]) -> u64 {
    items.iter().map(|(_, paise)| paise).sum()
}

fn main() {
    let items = vec![("dosa", 9_000), ("coffee", 3_500), ("vada", 4_250)];
    for (name, paise) in &items {
        println!("{name:<6} Rs {:>3}.{:02}", paise / 100, paise % 100);
    }
    let sum = total(&items);
    let count = items.len();
    println!("{count} items: Rs {}.{:02}", sum / 100, sum % 100);
}

Output

dosa   Rs  90.00
coffee Rs  35.00
vada   Rs  42.50
3 items: Rs 167.50

Recorded with rustc 1.99.0 (b940084d7) on macOS 26 arm64. To run it yourself: rustc --edition 2024 -O bill_total.rs && ./bill_total

Now two lines change. total takes the list itself, Vec<(&str, u64)>, instead of a borrowed view of it, and the call total(items) hands the list over. Line 12 still asks the list for its length:

bill_moved.rs: the list used after it was handed over Rust · bill_moved.rs
// The same bill with two changes: total() takes the list itself, and the call hands it over.
fn total(items: Vec<(&str, u64)>) -> u64 {
    items.iter().map(|(_, paise)| paise).sum()
}

fn main() {
    let items = vec![("dosa", 9_000), ("coffee", 3_500), ("vada", 4_250)];
    for (name, paise) in &items {
        println!("{name:<6} Rs {:>3}.{:02}", paise / 100, paise % 100);
    }
    let sum = total(items);
    let count = items.len();
    println!("{count} items: Rs {}.{:02}", sum / 100, sum % 100);
}

Output (exit status 1)

Printed as an error (standard error)

error[E0382]: borrow of moved value: `items`
  --> bill_moved.rs:12:17
   |
 7 |     let items = vec![("dosa", 9_000), ("coffee", 3_500), ("vada", 4_250)];
   |         ----- move occurs because `items` has type `Vec<(&str, u64)>`, which does not implement the `Copy` trait
...
11 |     let sum = total(items);
   |                     ----- value moved here
12 |     let count = items.len();
   |                 ^^^^^ value borrowed here after move
   |
note: consider changing this parameter type in function `total` to borrow instead if owning the value isn't necessary
  --> bill_moved.rs:2:17
   |
 2 | fn total(items: Vec<(&str, u64)>) -> u64 {
   |    -----        ^^^^^^^^^^^^^^^^ this parameter takes ownership of the value
   |    |
   |    in this function
help: consider cloning the value if the performance cost is acceptable
   |
11 |     let sum = total(items.clone());
   |                          ++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0382`.

Recorded with rustc 1.99.0 (b940084d7) on macOS 26 arm64. To run it yourself: rustc --edition 2024 -O bill_moved.rs && ./bill_moved

No program was built. The compiler points at items.len() on line 12 with ^^^^^, and its other labels tell the story: items was moved into total on line 11. Step through what the compiler follows to reach that error:

Interactive · step by step Who owns the list in bill_moved.rs Step through the program the way rustc reads it. Watch which name owns the list, and where the compiler stops.
Who owns the list in bill_moved.rs, step 7 of 7. Showing main: items (owns the list), The list (freed when total returned), total(items) (borrows it), items.len(), rustc, The program (built and run). In focus: main: items, total(items).ownshands it overmain: itemsowns the listThe listfreed when total returnedtotal(items)borrows ititems.len()line 12rustcchecks every useThe programbuilt and run

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. An owner. let items = vec![…] puts three items on the heap. The name items in main is their owner: each value in Rust has exactly one owner at a time.
  2. Borrowed by the loop. for … in &items reads the list through a borrow, a reference that lends it out for a while. main still owns it when the loop ends.
  3. Handed over. total(items) moves the list into total: its parameter becomes the new owner, and items in main no longer owns anything.
  4. Freed at the end. When total returns, its parameter goes out of scope, so the list is dropped and its memory freed, as the third ownership rule says.
  5. A use after the move. Line 12 asks items for its length. Run as written, it would ask a list that total has already freed.
  6. rustc refuses. The compiler follows every owner before it builds anything. It reports error E0382, borrow of moved value, and stops: no program is built, so nothing runs.
  7. The fix lends the list. In bill_total.rs, total takes &[(&str, u64)] and the call is total(&items): the function borrows the list, main keeps it, and line 12 compiles.

The rules behind this are few. Each value has one The variable that a value belongs to. Each value in Rust has exactly one owner at a time, and the value is dropped, its memory freed, when the owner goes out of scope. at a time, and when the owner goes out of scope the value is dropped and its memory freed. Passing a value to a function Hands a value over to a new owner, such as a function's parameter. The old name can no longer be used, and the compiler refuses any use of it after the move. it, unless the function only Uses a value through a reference (&) without taking it over. The owner keeps the value, and the compiler checks that the reference never outlives it. it with &. The compiler checks these rules before it builds anything, so a program that breaks them is never built.

Cloning to make the error go away

rustc’s last suggestion, total(items.clone()), compiles, but it copies the whole list only to add it up. Its note is the better fix here: let total borrow the list, &[(&str, u64)] and total(&items), as bill_total.rs does.

That is how Rust offers safety and speed together. The Rust book is explicit about the price of the checks: none of them slow a program down while it runs. There is no garbage collector looking for unused memory while the program runs, and none is needed, because the compiler has already worked out where each value is freed. And Rust is compiled ahead of time to machine code: the bill_total that ran above is a program of its own, which runs on another computer of the same kind without Rust installed.

Key idea

Rust follows who owns each value before it builds a program: code that would use memory after it was moved or freed is refused, and the checks cost nothing while the program runs.

Checkpoint

Check: What the compiler refuses

  1. Question 1 of 2 In the E0382 error for bill_moved.rs, which line does rustc mark with ^^^^^, the use it refuses?

    Choose one answer.

    A hint

    The ^^^^^ marks the place the error is about; the ----- labels explain how it came to be.

    Show the answer: Question 1 of 2

    Answer: Line 12, let count = items.len();

    The primary label, ^^^^^, is on line 12, where items is used after line 11 moved it into total. The secondary labels, -----, show the steps that led there, and the note at line 2 suggests the fix: let total borrow the list.

  2. Question 2 of 2 Which of these edits make bill_moved.rs compile? Choose every one that works.

    Choose every answer that is right.

    A hint

    The error needs items to still own the list at line 12, or line 12 to run before the list is handed over.

    Show the answer: Question 2 of 2

    Answer:

    • Call total(items.clone())
    • Move let count = items.len(); above let sum = total(items);
    • Let total borrow: total(items: &[(&str, u64)]) and total(&items)

    E0382 is about using a value after it was moved. Any edit that keeps an owner for line 12 works: borrowing instead of moving, giving total a copy, or reading the length before the move. Making the name mutable changes nothing about who owns the list.

Safe Rust still lets some mistakes through

Refusing to build is one of three things safe Rust can do with a mistake. Some mistakes show only while the program runs, and then Rust stops it with a panic: Rust's way of stopping a program, or one thread of it, at an error it cannot carry on from, such as an index past the end of a list. It prints the reason and the line, and a program whose main thread panics exits with status 101. before anything goes wrong in memory; others it does not treat as unsafe at all. This program makes one of each kind:

limits.rs: three mistakes in one program Rust · limits.rs
// Two mistakes safe Rust lets through, and one it stops while the program runs.
fn main() {
    // A u8 holds 0 to 255. Ten more bookings take 250 past the top.
    let mut booked: u8 = 250;
    for _ in 0..10 {
        booked += 1;
    }
    println!("seats booked: {booked}");

    // A logic error compiles: the 10% discount is taken twice.
    let price = 200;
    let discounted = price - price / 10;
    let charged = discounted - discounted / 10;
    println!("charged: {charged} (meant: {discounted})");

    // Reading past the end never happens: get() says None, and [] stops the program.
    let rows = vec![3, 5, 8];
    println!("rows.get(7): {:?}", rows.get(7));
    let wanted = rows.len() + 4;
    println!("rows[{wanted}] = {}", rows[wanted]);
}

The session builds it twice: first optimised, with -O, the way a release is built, then for debugging, the way rustc builds without -O:

limits.rs, optimised and then for debugging Python · limits_session.py
from session import run

# The program built twice: optimised, as a release is, and then for debugging, as rustc builds without -O.
run("""
rustc --edition 2024 -O limits.rs
!./limits
rustc --edition 2024 limits.rs -o limits-debug
!./limits-debug
""")

Output

$ rustc --edition 2024 -O limits.rs
$ ./limits
seats booked: 4
charged: 162 (meant: 180)
rows.get(7): None

thread 'main' (…) panicked at limits.rs:20:41:
index out of bounds: the len is 3 but the index is 7
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
[exit status 101]
$ rustc --edition 2024 limits.rs -o limits-debug
$ ./limits-debug

thread 'main' (…) panicked at limits.rs:6:9:
attempt to add with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
[exit status 101]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 limits_session.py

In the optimised build, 250 seats plus ten bookings printed 4: a u8 holds 0 to 255, and the count wrapped past the top without a word. The discount was taken twice, so the program charged 162 instead of 180; the compiler cannot know which formula you meant. rows.get(7) returned None, and rows[wanted] stopped the program before it read anything: a panic with the file, the line and the reason, and exit status 101. The debug build stopped earlier, at the overflow itself, because the Rust Reference requires a build with debug assertions to panic when arithmetic overflows.

The mistake What safe Rust does Where you see it
A value used after it was moved or freed Refuses to compile (E0382) bill_moved.rs
Two threads changing the same data without a lock Refuses to compile the threads lessons, later
A read past the end of a list Stops the program with a panic rows[wanted]
A number past its type’s limit Panics when built for debugging, wraps when optimised booked
A wrong formula Compiles and runs charged
A deadlock or a memory leak Allows it: not unsafe, though still a bug the Rust Reference

The last rows are easy to forget. The Reference lists deadlocks, memory leaks, integer overflow and logic errors as behaviour not considered unsafe, and the Rustonomicon says such problems are “considered impractical to categorically prevent”. What safe Rust promises is narrower and stronger: no undefined behaviour: What a program does once it breaks a rule the language relies on, such as reading memory that was freed: the language promises nothing about the result. Code written only in safe Rust never causes it., the class of bug after which the language promises nothing at all about how the program behaves.

Programmer Calculator (Bitwise) Add 250 and 10 at 8 bits, unsigned, and watch the result wrap to 4, as the optimised build did.

Trusting tests to catch overflow

Tests are built for debugging, so an overflow that a test reaches panics there. A case no test reaches still wraps silently in the optimised build that goes to users. Use checked_add, which returns None on overflow, wherever a value can pass its limit.

Checkpoint

Check: What safe Rust lets through

  1. Question 1 of 2 A u8 starts at 245, and an optimised build adds 1 to it twenty times, as limits.rs adds ten. What does it print?

    Type a number.

    A hint

    A u8 holds 0 to 255; one past 255 wraps to 0.

    Show the answer: Question 1 of 2

    Answer: 9

    245 + 20 is 265, which is 9 past 256, the number of values a u8 can hold. The optimised build does not check u8 arithmetic, so the value wraps silently: 255 + 1 becomes 0, and nine more steps make 9. A build for debugging would panic with "attempt to add with overflow" instead.

  2. Question 2 of 2 What does safe Rust do when a program indexes a Vec past its end, as rows[wanted] does?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It panics with "index out of bounds" before reading anything, and the program exits with status 101

    rows[wanted] is checked at run time: the index 7 is past the length 3, so the program panics with "index out of bounds: the len is 3 but the index is 7" and exits with status 101. rows.get(7) is the non-panicking way to ask.

A new stable Rust every six weeks, a new edition every few years

Rust’s compiler moves on a timetable. A new stable release ships every six weeks. Before it does, each release spends a cycle on the beta channel, and the nightly channel is built every night from the newest code, with features that are not finished yet. Editions are a separate thing: an edition is a set of language rules that each A unit of Rust code that the compiler builds as a whole: a library or a program. A Cargo package holds one or more crates. chooses in its Cargo.toml, so far one every three years: 2015, 2018, 2021 and 2024. Walk through the releases and editions this track depends on:

Timeline · 9 events in order Rust releases and editions that shape this track Walk through the releases in order. Each event says what that release brought.
  1. 1.0

    The first stable release

    Rust 1.0 came out in 2015 and ended the years of breaking changes before it. Its language is what is now called the 2015 edition.

  2. 1.31

    The 2018 edition edition

    Rust 1.31 brought the first new edition, Rust 2018. A crate chooses its edition in Cargo.toml, and crates of different editions still work together.

  3. 1.56

    The 2021 edition edition

    Rust 1.56 stabilised Rust 2021, the third edition, on the same rule. An older crate keeps compiling with its own edition on every newer compiler.

  4. 1.85

    The 2024 edition edition

    Rust 1.85 stabilised Rust 2024, with changes to the language, the standard library, Cargo, rustdoc and rustfmt. cargo new writes edition = "2024" since then, and this track uses it.

  5. 1.90

    Intel Macs move to Tier 2 platforms

    The x86_64-apple-darwin target moved from Tier 1 to Tier 2 with host tools, still built but no longer fully tested. Linux on x86-64 switched to the LLD linker by default.

  6. 1.91

    Windows on Arm joins Tier 1 platforms

    aarch64-pc-windows-msvc became a Tier 1 target, with the full test suite run for every change, and a new warning caught functions that return a dangling raw pointer to a local variable.

  7. 1.99.0

    The release this track uses this track

    Six weeks after 1.98, Rust 1.99.0 lets C-style variadic functions be defined in Rust and stabilises APIs such as Vec::into_parts. Every example in this track ran on it.

  8. 1.99.1

    A point release

    Rust 1.99.1 fixed three regressions of earlier releases, among them a linker that could fail to start on macOS when the compiler ran without rustup's proxy.

  9. 1.100

    Next on the train

    The next release spends six weeks on the beta channel and becomes stable six weeks after 1.99.0. The project's promise is that code that works on one stable release keeps working when you upgrade to the next.

The timeline has 9 events, from 1.0 to 1.100.

So two numbers describe how your code is compiled. The release, such as 1.99.0, changes when you upgrade the toolchain, and the project promises that code which works on one stable release keeps working on the next. The edition changes only when you change it in Cargo.toml: a crate on the 2021 edition stays on it with every newer compiler, and the rule the Edition Guide calls the most consequential is that crates of different editions work together. This track uses Rust 1.99.0 and the 2024 edition, which cargo new writes into every new package; the next lesson installs and pins that release.

The official book and this track

The Rust book now assumes Rust 1.97.0 or later with edition = "2024", so its examples and this track’s agree, and by the stability promise a newer stable compiler should build this track’s code too.

Checkpoint

Check: Releases and editions

  1. Question 1 of 2 Rust 1.99.0 is a stable release. When does the next feature release arrive, and what is it called?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 1.100.0, six weeks after 1.99.0

    The train ships a stable release every six weeks: 1.98.0, then 1.99.0, then 1.100.0. Point releases such as 1.99.1 fix regressions in between, and editions arrive on their own, much less often.

  2. Question 2 of 2 Your package uses the 2024 edition. Can it depend on a library crate that uses the 2021 edition?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Yes, crates of different editions work together

    Each crate chooses its edition in its own Cargo.toml, and the compiler builds each crate by its own edition's rules. That is why an ecosystem can move to a new edition one crate at a time.

Where Rust runs today, in the words of its users

Claims about Rust are easy to find and hard to check. These are the ones this track relies on, each from the organisation that published it:

Where What its publisher reports
Android Memory-safety bugs fell below 20 % of Android’s vulnerabilities in 2025, and Rust code had a 1,000 times lower density of them than Android’s C and C++ (Google’s security blog)
The Linux kernel Rust is an optional part of the kernel’s build, with Rust 1.85.0 as the minimum version (the kernel’s documentation)
Governments The US agencies CISA and NSA published joint guidance on adopting memory-safe languages
Developers The most admired language of the Stack Overflow 2025 survey (72 %), used by 14.8 % of all respondents and 23.1 % of those learning to code

Read the Android row carefully: it says memory-safety bugs became a smaller share, not that the other bugs went away, which is exactly what the previous section predicts. The same report finds that, for medium and large changes, Rust changes are rolled back about four times less often than C++ changes.

The compiler builds for far more than desktops. Its platform support page lists Tier 1 targets, “guaranteed to work”, for Linux, Windows and macOS on Apple silicon, and Tier 2 targets, “guaranteed to build”, that include WebAssembly (wasm32-wasip1) and small Arm microcontrollers (thumbv7m-none-eabi, which has no std, only the core and alloc parts of the standard library). Later modules of this track build for both.

The Rust project’s own survey is just as clear about the costs. Its survey for 2025, with 7,156 completed responses, again found slow compile times and disk use among the biggest worries, along with concern that the language keeps growing more complex. The rules that refused bill_moved.rs also take practice to learn, which is what the ownership module of this track is for.

Checkpoint

Check: Where Rust is used, from the sources

  1. Question 1 of 2 Which sentence does the Android report in this lesson support?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Memory-safety bugs fell below 20 % of Android's vulnerabilities, with far fewer of them in Rust code

    The figures are about memory safety: fewer such bugs, as a share and per line of code. They say nothing about speed and do not claim the end of every bug, which matches what safe Rust promises.

  2. Question 2 of 2 Which costs of Rust did the Rust project's own 2025 survey name among the biggest worries?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Slow compile times and disk use, and a language that keeps growing more complex

    The costs people report are paid while building, not while running: compile times and the disk space that builds use, plus a language with many features to learn.

Each run in this track shows its command, toolchain and output

No Rust compiler runs in this page, so every program in this track is shown with the output of a real run on Rust 1.99.0. A single program, such as bill_total.rs, shows the command that built and ran it, rustc --edition 2024 -O bill_total.rs && ./bill_total, and everything it printed. A session, such as the limits run above, shows several commands in a row: a line that starts with $ is a command, the lines under it are everything it printed, errors included, and [exit status 101] says how it ended when that was not 0. The few things that change on every run, such as build times and the number of the thread that panicked, are shown as …. Step through the parts of the limits session, from the script above its output to the note under it:

Interactive · step by step The parts of the limits session Step through the session shown above, from the script to the note under its output. Each step puts one part in focus.
The parts of the limits session, step 6 of 6. Showing limits_session.py, $ ./limits, seats booked: 4, thread 'main' (…), [exit status 101], Recorded with …. In focus: Recorded with ….limits_session.pythe script that played it$ ./limitsa command, as typedseats booked: 4what the command printedthread 'main' (…)… marks what varies[exit status 101]how the command endedRecorded with …the note under the output

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The script. Above the output is the script that played the session: one command a line, run in the folder of the example. A ! before a command says it is meant to fail, and the transcript leaves the ! out.
  2. A command. In the output, a line that starts with $ is one command, exactly as typed. ./limits runs the program that the rustc line before it built.
  3. What it printed. The lines under a command are everything it printed, normal output and error messages together, in the order it wrote them.
  4. What changes. A part that changes on every run is shown as …, such as the number of the thread that panicked or the time a build took, so two runs show the same text.
  5. How it ended. A command that does not end with status 0 gets a line of its own. A Rust program that panics in main ends with 101; a command that succeeds gets no such line.
  6. The note under it. The note under the output names Python 3.14.8, which played the script. The commands themselves ran Rust 1.99.0, the release that the folder of the session pins.

To repeat a run yourself, install Rust 1.99.0 (the next lesson does it), save the file in a folder, open a terminal there and type the commands that follow $. Your output should match, apart from the folder names and the … parts.

Checkpoint

Check: Reading a recorded run

  1. One question A session shows $ ./limits, three lines of output, a panic message and then [exit status 101]. What does the last line tell you?

    Choose one answer.

    Show the answer: One question

    Answer: The program ended with status 101, which is how a Rust program that panics ends

    Every session shows the command after $, everything it printed, and its exit status when that was not 0. A Rust program that panics in main exits with status 101; one that ends normally exits with 0 and gets no status line.

Practise: what does safe Rust do with each mistake?

Each question describes one mistake. Decide whether safe Rust refuses to compile it, stops it with a panic while the program runs, or lets it through, then read the explanation, which names the rule that decides. Your answers set the order: ideas you get wrong come back sooner than the ones you get right.

Practice that adapts to you

Practise this lesson

12 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 12 A function creates a String and returns a reference to it, &name, while name is a local variable of the function. What does safe Rust do?

    Choose one answer.

    Show the answer: Question 1 of 12

    Answer: Refuses to compile it, because name is dropped when the function returns

    name is dropped when its owner, the function, returns. A reference to it would point at freed memory, so the compiler refuses the function. The fix is to return the String itself, moving it to the caller.

  2. Question 2 of 12 Two threads push items onto the same Vec, with no lock around it. What does safe Rust do?

    Choose one answer.

    Show the answer: Question 2 of 12

    Answer: Refuses to compile it

    A data race is undefined behaviour, so safe Rust refuses code that could cause one. To share a Vec between threads you must put it behind a lock, such as a Mutex, which the threads lessons of this track show.

  3. Question 3 of 12 When are Rust's ownership rules checked, and what do they cost a running program?

    Choose one answer.

    Show the answer: Question 3 of 12

    Answer: When the program is compiled; they cost nothing while it runs

    Ownership is a compile-time check. That is why bill_moved.rs produced no program at all, and why bill_total.rs pays nothing for being checked.

  4. Question 4 of 12 A loop reads list[i] for i from 0 up to and including list.len(). What does safe Rust do?

    Choose one answer.

    Show the answer: Question 4 of 12

    Answer: It panics on the last pass, when i equals the length

    Indexes run from 0 to len() - 1. With i equal to len(), the bounds check fails, and the program panics with "index out of bounds", exit status 101.

  5. Question 5 of 12 A refund is computed as charge - refund with both values u64 in paise, in an optimised build, and the refund is larger. What happens?

    Choose one answer.

    Show the answer: Question 5 of 12

    Answer: The result wraps to a huge number close to 2 to the power 64, with no error

    Integer overflow is not considered unsafe in Rust. An optimised build wraps silently, here to 2^64 minus the difference, while a build for debugging panics. checked_sub returns None instead, which lets the code report the problem.

  6. Question 6 of 12 Two threads each take two locks, A then B in one thread and B then A in the other, and both wait for ever. What does safe Rust do?

    Choose one answer.

    Show the answer: Question 6 of 12

    Answer: Nothing stops it; a deadlock is not considered unsafe

    Safe Rust rules out undefined behaviour, and a deadlock is not undefined behaviour. The cure is a fixed order for taking locks, which the threads lessons cover.

  7. Question 7 of 12 How many weeks pass between two stable Rust releases?

    Type a number.

    Show the answer: Question 7 of 12

    Answer: 6 weeks

    Rust ships a stable release every six weeks, like a train timetable: 1.98.0, 1.99.0 and 1.100.0 are six weeks apart. Point releases such as 1.99.1 come in between only when a fix cannot wait.

  8. Question 8 of 12 Your crate's Cargo.toml says edition = "2021". You upgrade the compiler from 1.98 to 1.99. Which rules is your code compiled by now?

    Choose one answer.

    Show the answer: Question 8 of 12

    Answer: The 2021 edition's rules, by the 1.99 compiler

    Two numbers describe how a crate is compiled: the release of the toolchain, here 1.99, and the edition the crate declares, here 2021. Upgrading one leaves the other alone.

  9. Question 9 of 12 You want to cite a source for "Rust is used to build the Linux kernel". Which source settles it best?

    Choose one answer.

    Show the answer: Question 9 of 12

    Answer: The kernel's own documentation, which lists Rust 1.85.0 as the minimum version of an optional part of its build

    The best evidence of what a project uses is the project's own publication. The kernel's list of minimal requirements names Rust, with its minimum version, as an optional part of the build.

  10. Question 10 of 12 A colleague says: "Rust means Android has no more security bugs." Which correction matches the evidence?

    Choose one answer.

    Show the answer: Question 10 of 12

    Answer: Memory-safety bugs fell below 20 % of the vulnerabilities; other kinds of vulnerability remain

    Safe Rust removes a class of bug, memory-safety bugs, which is why their share and density fell. Logic errors and other vulnerabilities are still possible, as the second section of this lesson showed on a recorded run.

  11. Question 11 of 12 You want to repeat the limits session on your own computer. What do you do?

    Choose one answer.

    Show the answer: Question 11 of 12

    Answer: Install Rust 1.99.0, save limits.rs, and type the commands that follow $ in a terminal in that folder

    A session is a transcript: each $ line is a command, the lines under it are its output. With Rust 1.99.0 installed, typing the same commands in a folder with the same files gives the same output, apart from folder names and the parts shown as ….

  12. Question 12 of 12 What does bill_total.rs print? Work it out from the amounts in paise and the format strings, then compare with the recorded run.

    What does this program print? Choose one answer.

    // A canteen bill kept in paise, whole numbers, so no rounding error can creep in.
    fn total(items: &[(&str, u64)]) -> u64 {
        items.iter().map(|(_, paise)| paise).sum()
    }
    
    fn main() {
        let items = vec![("dosa", 9_000), ("coffee", 3_500), ("vada", 4_250)];
        for (name, paise) in &items {
            println!("{name:<6} Rs {:>3}.{:02}", paise / 100, paise % 100);
        }
        let sum = total(&items);
        let count = items.len();
        println!("{count} items: Rs {}.{:02}", sum / 100, sum % 100);
    }
    Show the answer: Question 12 of 12

    Answer: it prints

    dosa   Rs  90.00
    coffee Rs  35.00
    vada   Rs  42.50
    3 items: Rs 167.50

    Every amount is a whole number of paise. Integer division by 100 gives the rupees, the remainder gives the paise, and {:02} pads it to two digits, so 9,000 paise print as 90.00. The three amounts add up to 16,750 paise, Rs 167.50, exactly as the recorded run shows.

Interview questions

Warm-up: what does safe Rust guarantee, and what does it not?

Safe Rust guarantees memory safety and freedom from data races: code written only in safe Rust cannot use memory after it is freed, free it twice, read past the end of a buffer or let two threads change the same data without synchronisation. Most of these are refused at compile time, as E0382 refuses a use after a move; a read past the end of a list is stopped at run time with a panic. It does not guarantee a correct program. Deadlocks, memory leaks, logic errors and integer overflow are all possible in safe Rust: the Reference lists them as behaviour not considered unsafe, and an optimised build wraps an overflowing integer silently unless overflow checks are switched on. A strong answer adds that unsafe code inside a library must uphold the same rules, which is why its soundness matters.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Mid to senior

    Your team wants to rewrite a C++ library that parses uploaded image files in Rust, because "Rust has no bugs". What would the rewrite remove, what would it not, and how would you decide whether it is worth doing?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to mid

    A refund calculation subtracts two u64 amounts in paise. The tests pass, but in production a refund 100 paise larger than its charge produced 18,446,744,073,709,551,516 paise instead of an error. Why did the tests miss it, and what do you change?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • Rust follows who owns each value before it builds a program, so code that uses memory after it was moved or freed is refused, as bill_moved.rs was with E0382, and the checks cost nothing while the program runs.
  • Safe Rust stops a read past the end of a list with a panic, but it lets logic errors, deadlocks, leaks and, in an optimised build, integer wrap-around through.
  • A stable release ships every six weeks, while each crate chooses its edition in Cargo.toml, and crates of different editions work together.
  • Android’s figures, the Linux kernel’s documentation and the Stack Overflow survey show where Rust is used, and the Rust project’s survey names its costs: compile times, disk use and a growing language.
  • Every run in this track shows the command, the Rust 1.99.0 toolchain and exactly what was printed, with the exit status when it was not 0.

Terms in this lesson

edition
A set of language rules that each crate chooses in Cargo.toml: 2015, 2018, 2021 or 2024. A new edition changes nothing for crates that keep an older one, and crates of different editions work together.
panic
Rust's way of stopping a program, or one thread of it, at an error it cannot carry on from, such as an index past the end of a list. It prints the reason and the line, and a program whose main thread panics exits with status 101.
undefined behaviour
What a program does once it breaks a rule the language relies on, such as reading memory that was freed: the language promises nothing about the result. Code written only in safe Rust never causes it.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.