We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Ownership II: Borrowing and the Borrow Checker step 8 of 24
Accessing an owned value while it is borrowed
Repair the borrow error in settle. It owns an account, applies each
balance change, and returns the final balance together with the history.
pub struct Account {
pub id: i64,
pub balance: i64,
pub history: Vec<i64>,
}
pub fn settle(mut a: Account, deltas: &[i64]) -> (i64, Vec<i64>)
For each delta, add it to balance, then append the new balance to
history. Preserve all existing history entries. Even a zero delta adds
an entry. Empty deltas leave both the balance and history unchanged.
balance 100, history [], deltas [] -> (100, [])
balance 0, history [], deltas [-5,-10] -> (-15, [-5,-15])
balance 10, history [10], deltas [5] -> (15, [10,15])
All intermediate sums in the test inputs fit in i64. The account ID
does not affect settlement. Move the history vector into the result without
cloning it; normal vector growth while appending is allowed.
Ownership does not cancel a borrow
Owning a value lets you lend access to it, but you must still respect that access while the borrow is needed. The starter borrows the entire account, moves its history, then reads through the earlier borrow:
let acct = &a;
let history = a.history; // E0505: the account is still borrowed.
(acct.balance, history)
This is an excerpt from the failing function. The final use of acct
keeps the whole-account borrow active across the field move. Moving the
field would leave the borrowed account partially moved.
The needed outputs are available directly from the owned account. Reading
a.balance copies an i64; reading a.history by value moves a
Vec<i64>. Removing the unnecessary whole-account reference allows both.
You could also copy the balance into a local variable before moving the history. The key is avoiding an overlapping whole-account borrow, not relying on a special tuple-expression rule.
Recognize the conflicting operation
These diagnostics describe related borrow conflicts:
| Code | Typical conflict |
|---|---|
| E0506 | Assigning to a place while a borrow of it is still needed |
| E0505 | Moving a value while it is still borrowed |
| E0503 | Reading or otherwise using a place while a mutable borrow is still needed |
When reading an error, find where the borrow starts, the conflicting operation, and the later use that keeps the borrow active. In this complete example, moving the read before the mutable borrow avoids the conflict:
fn main() {
let mut number = 1;
let previous = number;
let borrowed = &mut number;
*borrowed += 1;
assert_eq!(previous, 1);
assert_eq!(number, 2);
}
Moving let previous = number; between the creation and use of
borrowed produces E0503.
Borrow restrictions concern the borrowed place and conflicting accesses, not every operation on the owner. For example, shared reads may coexist, and borrowing one struct field can leave a disjoint field accessible. Interior-mutability types provide separate rules for permitted mutation.
Copying a field and moving a field
i64 implements Copy; Vec<i64> does not. Moving a vector transfers
ownership of its buffer instead of duplicating its elements. The account
cannot implement Copy while it contains that vector.
A struct whose fields all implement Copy can derive or implement
Copy, but does not acquire it automatically. Also, whether extracting
a field copies it depends on the field's type, not on whether the enclosing
struct implements Copy.
Cloning the history could produce the same output values, but would not meet this exercise's ownership-transfer requirement. Output tests alone cannot establish the absence of a clone.
A passing submission must compile, pass the tests, and pass
clippy -D warnings.
Loading visualization…
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.