Consider this Rust code snippet. What will it print when run?
fn main() {
let r;
{
let x = 5;
r = &x;
}
println!("{}", r);
}Think about the scope of x and the reference r.
The variable x is created inside the inner block and goes out of scope when the block ends. The reference r tries to borrow x but outlives x. Rust's borrow checker prevents this with a compile-time error.
Why does Rust sometimes require you to write explicit lifetime annotations in function signatures?
Think about what lifetimes describe in Rust.
Lifetimes specify how long references are valid. When the compiler cannot infer this automatically, you must write explicit lifetime annotations to ensure references do not outlive the data they point to.
What lifetime-related error will this Rust code produce?
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let string1 = String::from("long string");
let result;
{
let string2 = String::from("short");
result = longest(string1.as_str(), string2.as_str());
}
println!("{}", result);
}Look at the function longest and its return type.
The function longest returns a reference but does not specify lifetimes. The compiler cannot guarantee the returned reference is valid because it depends on the inputs' lifetimes. This causes a compile-time error.
Which of the following Rust function signatures correctly uses lifetime annotations for a function that returns a reference to one of its string slice parameters?
Consider which parameters the returned reference can validly point to.
Option B correctly declares two lifetimes for the two parameters and returns a reference with lifetime 'a, matching the first parameter. This is valid if the returned reference is from the first parameter.
Option B is invalid because the second parameter lacks a lifetime annotation but is mixed with 'a.
Option B lacks any lifetime annotations, causing a compile error.
Option B incorrectly assigns lifetime 'a to the first parameter without annotation.
What will this Rust program print?
fn main() {
let string1 = String::from("abcd");
let string2 = "xyz";
let result = longest(string1.as_str(), string2);
println!("{}", result);
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}Check which string slice is longer and the lifetimes involved.
The function longest returns the longer string slice. Here, string1 is "abcd" (length 4) and string2 is "xyz" (length 3). So it returns "abcd". The lifetimes are compatible because both references live long enough.