02open 25 min

Ownership and borrowing: the concept Python never forced you to name

Understand how Rust controls who owns data, who can borrow it, and when mutation is allowed.

by the end of this lesson you can

  • Chooses borrowing versus ownership intentionally
  • Makes mutation explicit in the function signature
  • Avoids unnecessary cloning to escape the ownership model

Overview

Python developers are used to object references, garbage collection, and mutation that mostly works until it becomes someone else's problem. Rust makes data ownership explicit and uses borrowing rules to keep mutation and aliasing under control.

In Python, you often

pass objects around freely and assume the runtime will keep them alive as long as some reference still exists.

In Rust, the common pattern is

to model who owns a value, when it is moved, and whether code only needs an immutable or mutable borrow.

why this difference matters

Once this clicks, much of Rust stops feeling arbitrary. Ownership is the reason many later rules exist.

Python

items = ["a", "b"]
process(items)
print(items)

Rust

let items = vec!["a", "b"];
process(items);
// items can no longer be used here if ownership moved

Deeper comparison

Python version

def add_tag(tags, value):
    tags.append(value)

values = ["rust"]
add_tag(values, "python")

Rust version

fn add_tag(tags: &mut Vec<&str>, value: &str) {
    tags.push(value);
}

let mut values = vec!["rust"];
add_tag(&mut values, "python");

Reflect

What kinds of bugs is Rust preventing when it forces you to distinguish owned values from borrowed references?

what a strong answer notices

A strong answer mentions invalid references, unclear mutation, and aliasing bugs that Python largely leaves to runtime behavior and discipline.

Rewrite

Rewrite this Python mutating helper into Rust and decide whether the function should take ownership or borrow mutably.

Rewrite this Python

def rename(user, new_name):
    user.name = new_name

what good looks like

  • Chooses borrowing versus ownership intentionally
  • Makes mutation explicit in the function signature
  • Avoids unnecessary cloning to escape the ownership model

Practice

Design a Rust function that reads a list of usernames and returns a new filtered list without mutating the original input.

success criteria

  • Explains whether the input should be borrowed or owned
  • Keeps mutation local to the new output value
  • Shows how ownership influences API shape

Common mistakes

  • Cloning aggressively instead of understanding ownership flow.
  • Using mutable references as the default rather than as a specific need.
  • Thinking of borrowing rules as syntax trivia instead of core program design.

takeaways

  • Once this clicks, much of Rust stops feeling arbitrary. Ownership is the reason many later rules exist.
  • A strong answer mentions invalid references, unclear mutation, and aliasing bugs that Python largely leaves to runtime behavior and discipline.
  • Explains whether the input should be borrowed or owned