yoklainterview sim

Backend Rs Ownership Borrowing Lifetimes Interview Questions

75 verified Backend Rs Ownership Borrowing Lifetimes interview questions — solve with answers, learn from explanations, test yourself in a real simulation.

Try the real simulation →

Sample questions

Rs Ownership Borrowing LifetimesDifficulty 1
fn main() {
    let s = String::from("hi");
    let t = s;
    println!("{} {}", s, t);
}

What does the compiler report?
  • aIt prints hi hi; let t = s copies the string bytes into t
  • bError E0499: s and t are two mutable owners of the same heap buffer
  • cError E0382: s was moved into t and is used afterwards
  • dIt compiles and prints hi once; s becomes an empty string after the assignment
Explanation:String owns a heap buffer and is not Copy, so let t = s moves ownership to t. The compiler then rejects the later read of s with E0382 (borrow of moved value). Nothing is copied and s does not become empty; it is simply no longer usable.
Rs Ownership Borrowing LifetimesDifficulty 1
fn main() {
    let a = 5;
    let b = a;
    println!("{} {}", a, b);
}

What happens?
  • aIt compiles and prints 5 5; i32 is Copy, so a stays valid after b = a
  • bError E0382; a is moved into b exactly like a String binding would be
  • cIt prints 5 5 only because the constant is folded; a runtime value would be moved
  • dError E0502; b holds a shared borrow of a while println! requests another one
Explanation:Integer types implement Copy, so assignment copies the bits and both bindings remain usable. Whether the value is a constant or computed at runtime makes no difference; the rule depends only on the type.
Rs Ownership Borrowing LifetimesDifficulty 2
fn consume(s: String) -> usize {
    s.len()
}

fn main() {
    let s = String::from("hello");
    let n = consume(s);
    println!("{} {}", n, s);
}

What does the compiler say, and what is the idiomatic fix when the callee only needs to read the string?
  • aIt prints 5 hello; arguments are passed as a copy of the pointer, so s is untouched
  • bE0505: consume keeps a borrow of s alive until the function returns
  • cIt prints 5 hello; ownership returns to the caller automatically when consume finishes
  • dE0382 at the println!; change the parameter to &str and call consume(&s) instead
Explanation:A String parameter takes ownership, so consume(s) moves s and the later println! is E0382. Ownership does not come back on return unless the function returns the value. Borrowing (&str or &String) lets the caller keep using s.
Rs Ownership Borrowing LifetimesDifficulty 1
fn len(s: &String) -> usize {
    s.len()
}

fn main() {
    let s = String::from("hello");
    let n = len(&s);
    println!("{} {}", n, s);
}

What is printed?
  • aNothing; the program fails with E0382 at the println! line
  • bIt compiles and prints 5 hello; &s only lends the string to len
  • c5 followed by a panic; the borrow is released when len returns and s is freed
  • d5 with an empty string; a shared borrow moves the heap buffer temporarily
Explanation:Passing &s creates a shared reference; ownership never leaves main. When len returns, the borrow simply ends and s is still fully usable. The value is neither moved nor freed.
Rs Ownership Borrowing LifetimesDifficulty 2
fn add(s: &mut String) {
    s.push('!');
}

fn main() {
    let s = String::from("hi");
    add(&mut s);
    println!("{}", s);
}

What does the compiler report?
  • aE0499: add and println! both need a mutable borrow of s at the same time
  • bIt compiles and prints hi!; &mut on the call site is what makes a binding mutable
  • cE0382: &mut s moves the string into add, so the later print uses a moved value
  • dE0596: cannot borrow s as mutable because the binding is not declared mut
Explanation:Taking &mut s requires that s itself be declared with let mut. The compiler rejects the call with E0596. Adding mut to the declaration makes it compile and print hi!; a mutable borrow does not move the value.
Rs Ownership Borrowing LifetimesDifficulty 2
fn main() {
    let mut s = String::from("hi");
    let a = &mut s;
    let b = &mut s;
    a.push('a');
    b.push('b');
    println!("{}", s);
}

What happens?
  • aE0499: b is a second mutable borrow of s while a is still used later
  • bIt compiles and prints hiab; two &mut are fine as long as they are used one after another
  • cE0502: println! takes a shared borrow while a and b are mutable borrows
  • dIt prints hib; the second &mut replaces the first one
Explanation:Only one mutable borrow may be live at a time. a is still used after b is created, so both are live at let b = &mut s, and the compiler reports E0499. If a.push('a') came before let b, the first borrow would have ended and the code would compile.

Test yourself against the 3750-question Backend bank.

Start interview