📖 Scenario: Imagine you are managing a small library system. You want to keep track of book titles and their authors. You need to make sure that when you refer to an author, the reference is always valid and does not point to something that no longer exists.
🎯 Goal: Build a simple Rust program that stores book titles and authors safely using references. You will learn how Rust prevents dangling references by enforcing borrowing rules.
📋 What You'll Learn
Create a variable holding an author's name as a string
Create a variable holding a book title as a string
Create a reference to the author's name
Print the book title and the author's name using the reference
💡 Why This Matters
🌍 Real World
Managing data safely in programs where references to data must not become invalid, such as in libraries, databases, or user interfaces.
💼 Career
Understanding Rust's ownership and borrowing rules is essential for writing safe and efficient systems software, embedded applications, and backend services.
Progress0 / 4 steps
1
Create author and book variables
Create a variable called author with the value "Jane Austen" and a variable called book with the value "Pride and Prejudice".
Rust
Hint
Use let to create variables and assign string slices.
2
Create a reference to the author
Create a variable called author_ref that is a reference to the author variable.
Rust
Hint
Use & to create a reference to a variable.
3
Use the reference in a print statement
Use println! to print the book title and the author's name by using the author_ref reference. The output should be: Pride and Prejudice by Jane Austen.
Rust
Hint
Use println!("{} by {}", book, author_ref); to print the values.
4
Run and observe the output
Run the program and observe the output. It should display: Pride and Prejudice by Jane Austen.
Rust
Hint
Make sure you run the program to see the printed output.
Practice
(1/5)
1. What does Rust do to prevent dangling references?
easy
A. It automatically deletes all references after use.
B. It enforces borrowing rules and lifetimes to ensure references are valid.
C. It uses garbage collection to clean up unused references.
D. It allows references to point to any memory without checks.
Solution
Step 1: Understand what dangling references are
Dangling references point to data that no longer exists, causing bugs.
Step 2: Identify Rust's prevention method
Rust uses borrowing rules and lifetimes to ensure references are always valid while used.
Final Answer:
It enforces borrowing rules and lifetimes to ensure references are valid. -> Option B
Hint: Remember: Rust checks lifetimes to avoid invalid references [OK]
Common Mistakes:
Thinking Rust uses garbage collection
Believing references are deleted automatically
Assuming Rust allows unchecked references
2. Which of the following Rust code snippets correctly prevents a dangling reference?
easy
A. let r;
{
let x = 5;
r = &x;
}
println!("{}", r);
B. let r = &5;
println!("{}", r);
C. let r = &x;
let x = 5;
println!("{}", r);
D. let x = 5;
let r = &x;
println!("{}", r);
Solution
Step 1: Analyze each snippet for lifetime validity
let r;
{
let x = 5;
r = &x;
}
println!("{}", r); creates a reference to x inside a block, but x is dropped before use, causing dangling reference. let r = &5;
println!("{}", r); creates a reference to a temporary value 5, which is dropped while borrowed, causing compile error. let x = 5;
let r = &x;
println!("{}", r); creates x and r in the same scope, so r is valid. let r = &x;
let x = 5;
println!("{}", r); tries to reference x before x is declared, so x not in scope, compile error.
Step 2: Identify the snippet that correctly prevents dangling references
let x = 5;
let r = &x;
println!("{}", r); is the correct example where the reference r points to x which lives long enough for r to be used safely.
Final Answer:
let x = 5; let r = &x; println!("{}", r); -> Option D
Quick Check:
Reference lifetime valid in same scope = let x = 5;
let r = &x;
println!("{}", r); [OK]
Hint: Keep referenced data alive in the same scope as the reference [OK]
Common Mistakes:
Referencing variables that go out of scope too early
Declaring references before the data they point to
Assuming temporary values always live long enough
3. What will be the output of this Rust code?
fn main() {
let r;
{
let x = 10;
r = &x;
}
println!("{}", r);
}
medium
A. Compilation error due to dangling reference
B. 10
C. Undefined behavior at runtime
D. 0
Solution
Step 1: Understand variable lifetimes in the code
Variable x is declared inside the inner block and dropped when the block ends. Reference r points to x but is used outside the block.
Step 2: Identify Rust's behavior on this code
Rust's compiler detects that r would be a dangling reference because x does not live long enough. It will produce a compilation error.
Final Answer:
Compilation error due to dangling reference -> Option A
Quick Check:
Dangling reference causes compile error in Rust [OK]
Hint: References must not outlive the data they point to [OK]
Common Mistakes:
Expecting code to run and print 10
Thinking Rust allows unsafe dangling references
Confusing runtime errors with compile-time errors
4. Identify the error in this Rust code and how to fix it:
fn get_ref() -> &i32 {
let x = 42;
&x
}
medium
A. Error: missing lifetime annotation. Fix by adding explicit lifetime.
B. No error, code is correct.
C. Error: returning reference to local variable. Fix by returning the value instead.
D. Error: x is not mutable. Fix by declaring x as mutable.
Solution
Step 1: Analyze the function's return type and variable scope
The function returns a reference to an integer, but x is a local variable that is dropped when the function ends.
Step 2: Identify the problem and fix
Returning a reference to a local variable causes a dangling reference. The fix is to return the value itself (i32) instead of a reference.
Final Answer:
Error: returning reference to local variable. Fix by returning the value instead. -> Option C
Quick Check:
Don't return references to local variables [OK]
Hint: Never return references to variables that go out of scope [OK]
Common Mistakes:
Adding lifetimes without fixing the root cause
Making variables mutable unnecessarily
Ignoring that local variables are dropped after function ends
5. You want to return a reference to a string slice from a function without causing dangling references. Which approach is correct?
fn first_word(s: &String) -> &str {
// ???
}
hard
A. Return a slice of s using lifetimes: &s[..1]
B. Create a new String inside the function and return a reference to it
C. Return a reference to a local string variable inside the function
D. Return the whole String by value instead of a reference
Solution
Step 1: Understand the input and output lifetimes
The function takes a reference to a String and returns a string slice (&str) referencing part of that String.
Step 2: Choose the safe way to return a slice without dangling references
Returning a slice of the input String (&s[..1]) is safe because the slice's lifetime is tied to the input reference's lifetime.
Final Answer:
Return a slice of s using lifetimes: &s[..1] -> Option A
Quick Check:
Return slices tied to input lifetimes to avoid dangling references [OK]
Hint: Return slices of input references, not local variables [OK]
Common Mistakes:
Returning references to local variables
Creating new owned Strings and returning references to them
Ignoring lifetime relationships between input and output
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.