
M14 Mental Model
- 1.4k installs
- 1.3k repo stars
- Updated May 24, 2026
- actionbook/rust-skills
m14-mental-model is an agent skill for explain rust ownership, borrow checker, and memory layout with mental models and analogies.
About
The m14-mental-model skill is designed for explain Rust ownership, borrow checker, and memory layout with mental models and analogies. Mental Models > Layer 2: Design Choices Core Question What's the right way to think about this Rust concept? When learning or explaining Rust: What's the correct mental model? Invoke when the user asks how to think about ownership, borrow checker, or Rust misconceptions.
- What's the correct mental model?.
- What misconceptions should be avoided?.
- What analogies help understanding?.
M14 Mental Model by the numbers
- 1,438 all-time installs (skills.sh)
- +51 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #12 of 129 Rust skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
m14-mental-model capabilities & compatibility
- Capabilities
- what's the correct mental model? · what misconceptions should be avoided? · what analogies help understanding?
What m14-mental-model says it does
Use when learning Rust concepts. Keywords: mental model, how to think about ownership, understanding borrow checker, visualizing memory layout, analogy, misconception, explaining o
Use when learning Rust concepts. Keywords: mental model, how to think about ownership, understanding borrow checker, visualizing memory layout, analogy, misconc
npx skills add https://github.com/actionbook/rust-skills --skill m14-mental-modelAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.4k |
|---|---|
| repo stars | ★ 1.3k |
| Security audit | 3 / 3 scanners passed |
| Last updated | May 24, 2026 |
| Repository | actionbook/rust-skills ↗ |
How do I explain rust ownership, borrow checker, and memory layout with mental models and analogies?
Explain Rust ownership, borrow checker, and memory layout with mental models and analogies.
Who is it for?
Learners building intuition for ownership, borrowing, and lifetimes in Rust.
Skip if: Skip for advanced unsafe FFI without conceptual teaching goals.
When should I use this skill?
User asks how to think about ownership, borrow checker, or Rust misconceptions.
What you get
Completed m14-mental-model workflow with documented commands, files, and expected deliverables.
- Ownership and borrowing mental model
- Scope-drop code examples
- Borrow-checker error prevention patterns
Files
Mental Models
Layer 2: Design Choices
Core Question
What's the right way to think about this Rust concept?
When learning or explaining Rust:
- What's the correct mental model?
- What misconceptions should be avoided?
- What analogies help understanding?
---
Key Mental Models
| Concept | Mental Model | Analogy |
|---|---|---|
| Ownership | Unique key | Only one person has the house key |
| Move | Key handover | Giving away your key |
&T | Lending for reading | Lending a book |
&mut T | Exclusive editing | Only you can edit the doc |
Lifetime 'a | Valid scope | "Ticket valid until..." |
Box<T> | Heap pointer | Remote control to TV |
Rc<T> | Shared ownership | Multiple remotes, last turns off |
Arc<T> | Thread-safe Rc | Remotes from any room |
---
Coming From Other Languages
| From | Key Shift |
|---|---|
| Java/C# | Values are owned, not references by default |
| C/C++ | Compiler enforces safety rules |
| Python/Go | No GC, deterministic destruction |
| Functional | Mutability is safe via ownership |
| JavaScript | No null, use Option instead |
---
Thinking Prompt
When confused about Rust:
1. What's the ownership model?
- Who owns this data?
- How long does it live?
- Who can access it?
2. What guarantee is Rust providing?
- No data races
- No dangling pointers
- No use-after-free
3. What's the compiler telling me?
- Error = violation of safety rule
- Solution = work with the rules
---
Trace Up ↑
To design understanding (Layer 2):
"Why can't I do X in Rust?"
↑ Ask: What safety guarantee would be violated?
↑ Check: m01-m07 for the rule being enforced
↑ Ask: What's the intended design pattern?---
Trace Down ↓
To implementation (Layer 1):
"I understand the concept, now how do I implement?"
↓ m01-ownership: Ownership patterns
↓ m02-resource: Smart pointer choice
↓ m07-concurrency: Thread safety---
Common Misconceptions
| Error | Wrong Model | Correct Model |
|---|---|---|
| E0382 use after move | GC cleans up | Ownership = unique key transfer |
| E0502 borrow conflict | Multiple writers OK | Only one writer at a time |
| E0499 multiple mut borrows | Aliased mutation | Exclusive access for mutation |
| E0106 missing lifetime | Ignoring scope | References have validity scope |
E0507 cannot move from &T | Implicit clone | References don't own data |
Deprecated Thinking
| Deprecated | Better |
|---|---|
| "Rust is like C++" | Different ownership model |
| "Lifetimes are GC" | Compile-time validity scope |
| "Clone solves everything" | Restructure ownership |
| "Fight the borrow checker" | Work with the compiler |
"unsafe to avoid rules" | Understand safe patterns first |
---
Ownership Visualization
Stack Heap
+----------------+ +----------------+
| main() | | |
| s1 ─────────────────────> │ "hello" |
| | | |
| fn takes(s) { | | |
| s2 (moved) ─────────────> │ "hello" |
| } | | (s1 invalid) |
+----------------+ +----------------+
After move: s1 is no longer validReference Visualization
+----------------+
| data: String |────────────> "hello"
+----------------+
↑
│ &data (immutable borrow)
│
+------+------+
| reader1 reader2 (multiple OK)
+------+------+
+----------------+
| data: String |────────────> "hello"
+----------------+
↑
│ &mut data (mutable borrow)
│
+------+
| writer (only one)
+------+---
Learning Path
| Stage | Focus | Skills |
|---|---|---|
| Beginner | Ownership basics | m01-ownership, m14-mental-model |
| Intermediate | Smart pointers, error handling | m02, m06 |
| Advanced | Concurrency, unsafe | m07, unsafe-checker |
| Expert | Design patterns | m09-m15, domain-* |
---
Related Skills
| When | See |
|---|---|
| Ownership errors | m01-ownership |
| Smart pointers | m02-resource |
| Concurrency | m07-concurrency |
| Anti-patterns | m15-anti-pattern |
Thinking in Rust: Mental Models
Core Mental Models
1. Ownership as Resource Management
Traditional: "Who has a pointer to this data?"
Rust: "Who OWNS this data and is responsible for freeing it?"Key insight: Every value has exactly one owner. When the owner goes out of scope, the value is dropped.
{
let s = String::from("hello"); // s owns the String
// use s...
} // s goes out of scope, String is dropped (memory freed)2. Borrowing as Temporary Access
Traditional: "I'll just read from this pointer"
Rust: "I'm borrowing this value, owner still responsible for it"Key insight: Borrows are like library books - you can read them, but must return them.
fn print_length(s: &String) { // borrows s
println!("{}", s.len());
} // borrow ends, caller still owns s
let my_string = String::from("hello");
print_length(&my_string); // lend to function
println!("{}", my_string); // still have it3. Lifetimes as Validity Scopes
Traditional: "Hope this pointer is still valid"
Rust: "Compiler tracks exactly how long references are valid"Key insight: A reference can't outlive the data it points to.
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
// 'a means: the returned reference is valid as long as BOTH inputs are valid
if x.len() > y.len() { x } else { y }
}---
Shifting Perspectives
From "Everything is a Reference" (Java/C#)
Java mental model:
// Everything is implicitly a reference
User user = new User("Alice"); // user is a reference
List<User> users = new ArrayList<>();
users.add(user); // shares the reference
user.setName("Bob"); // affects the list too!Rust mental model:
// Values are owned, sharing is explicit
let user = User::new("Alice"); // user is owned
let mut users = vec![];
users.push(user); // user moved into vec, can't use user anymore
// user.set_name("Bob"); // ERROR: user was moved
// If you need sharing:
use std::rc::Rc;
let user = Rc::new(User::new("Alice"));
let user2 = Rc::clone(&user); // explicit shared ownershipFrom "Manual Memory Management" (C/C++)
C mental model:
char* s = malloc(100);
// ... must remember to free(s) ...
// ... what if we return early? ...
// ... what if an exception occurs? ...
free(s);Rust mental model:
let s = String::with_capacity(100);
// ... use s ...
// No need to free - Rust drops s automatically when scope ends
// Even with early returns, panics, or any control flowFrom "Garbage Collection" (Go/Python)
GC mental model:
# Create objects, GC will figure it out
users = []
for name in names:
users.append(User(name))
# GC runs sometime later, when it feels like itRust mental model:
let users: Vec<User> = names
.iter()
.map(|name| User::new(name))
.collect();
// Memory is freed EXACTLY when users goes out of scope
// Deterministic, no GC pauses, no unpredictable memory usage---
Key Questions to Ask
When Designing Functions
1. Does this function need to own the data, or just read it?
- Need to keep it: take ownership (
fn process(data: Vec<T>)) - Just reading: borrow (
fn process(data: &[T])) - Need to modify: mutable borrow (
fn process(data: &mut Vec<T>))
2. Does the return value contain references to inputs?
- Yes: need lifetime annotations
- No: lifetime elision usually works
When Designing Structs
1. Should this struct own its data or reference it?
- Long-lived, independent: own (
name: String) - Short-lived view: reference (
name: &'a str)
2. Do multiple parts need to access the same data?
- Single-threaded:
Rc<T>orRc<RefCell<T>> - Multi-threaded:
Arc<T>orArc<Mutex<T>>
When Hitting Borrow Checker Errors
1. Am I trying to use a value after moving it?
- Clone it, borrow it, or restructure the code
2. Am I trying to have multiple mutable references?
- Scope the mutations, use interior mutability, or redesign
3. Does a reference outlive its source?
- Return owned data instead, or use
'static
---
Common Patterns
The Clone Escape Hatch
When fighting the borrow checker, .clone() often works:
// Can't do this - double borrow
let mut map = HashMap::new();
for key in map.keys() {
map.insert(key.clone(), process(key)); // ERROR: map borrowed twice
}
// Clone to escape
let keys: Vec<_> = map.keys().cloned().collect();
for key in keys {
map.insert(key.clone(), process(&key)); // OK
}But ask: "Is there a better design?" Often, restructuring is better than cloning.
The "Make It Own" Pattern
When lifetimes get complex, make the struct own its data:
// Complex: struct with references
struct Parser<'a> {
input: &'a str,
current: &'a str,
}
// Simpler: struct owns data
struct Parser {
input: String,
position: usize,
}The "Split the Borrow" Pattern
struct Data {
field_a: Vec<i32>,
field_b: Vec<i32>,
}
// Can't borrow self mutably twice
fn process(&mut self) {
// for a in &self.field_a {
// self.field_b.push(*a); // ERROR
// }
// Split the borrow
let Data { field_a, field_b } = self;
for a in field_a.iter() {
field_b.push(*a); // OK: separate borrows
}
}---
The Rust Way
Embrace the Type System
// Don't: stringly-typed
fn connect(host: &str, port: &str) { ... }
connect("8080", "localhost"); // oops, wrong order
// Do: strongly-typed
struct Host(String);
struct Port(u16);
fn connect(host: Host, port: Port) { ... }
// connect(Port(8080), Host("localhost".into())); // compile error!Make Invalid States Unrepresentable
// Don't: runtime checks
struct Connection {
socket: Option<Socket>,
connected: bool,
}
// Do: types enforce states
enum Connection {
Disconnected,
Connected { socket: Socket },
}Let the Compiler Guide You
// Start with what you want
fn process(data: ???) -> ???
// Let compiler errors tell you:
// - What types are needed
// - What lifetimes are needed
// - What bounds are needed
// The error messages are documentation!---
Summary: The Rust Mental Model
1. Values have owners - exactly one at a time 2. Borrowing is lending - temporary access, owner retains responsibility 3. Lifetimes are scopes - compiler tracks validity 4. Types encode constraints - use them to prevent bugs 5. The compiler is your friend - work with it, not against it
When stuck:
- Clone to make progress
- Restructure to own instead of borrow
- Ask: "What is the compiler trying to tell me?"
Related skills
Forks & variants (1)
M14 Mental Model has 1 known copy in the catalog totaling 764 installs. They canonicalize to this original listing.
- zhanghandong - 764 installs
How it compares
Pick m14-mental-model over m12-lifecycle when the blocker is understanding ownership and borrows, not designing connection pools or resource scopes.
FAQ
What does m14-mental-model do?
Explain Rust ownership, borrow checker, and memory layout with mental models and analogies.
When should I use m14-mental-model?
User asks how to think about ownership, borrow checker, or Rust misconceptions.
Is m14-mental-model safe to install?
Review the Security Audits panel on this page before installing in production.