agentleFS
huialihuiali/rust-skills/skills/rust-ownership/SKILL.md

rust-ownership

Skill47 starsChanged 9 months agoMITView on GitHub

Ownership, borrowing, and lifetime expert. Handles compiler errors E0382, E0597, E0506, E0507, E0515, E0716, E0106 and provides systematic solutions for memory safety patterns.

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 8 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈8

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Only need to read → pass by reference &s1

    line 32
  2. Distinctive:

    Ensure mutable borrow completes before creating new borrows

    line 47
  3. Distinctive:

    Use named lifetimes to express relationships

    line 62
  4. Distinctive:

    Prefer returning owned types

    line 63
  5. Very specific:

    Use meaningful names: 'connection, 'file

    line 131
  6. Distinctive:

    Check borrow scope ranges

    line 135
  7. Distinctive:

    When encountering ownership issues, follow these steps:

    line 154
  8. Distinctive:

    If failed 3 times → escalate to design level

    line 166
  9. Distinctive:

    When ownership errors persist, trace to design level:

    line 171
  10. Distinctive:

    When reviewing ownership-related code:

    line 207

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Solution Patterns

Pattern 1: Value Moved After Use

let s1 = String::from("hello");
let s2 = s1;
// println!("{}", s1); // Compile error!

Root Cause: Ownership transferred from s1 to s2, s1 is no longer valid.

Solutions:

  • Need two copies → use clone()
  • Only need to read → pass by reference &s1
  • s2 is temporary → consider redesign

Pattern 2: Borrow Conflict

let mut s = String::from("hello");
let r1 = &s;
let r2 = &mut s; // Conflict!
// println!("{}", r1);

Root Cause: Immutable and mutable borrows coexist.

Solutions:

  • Ensure mutable borrow completes before creating new borrows
  • Restructure code organization

Pattern 3: Lifetime Mismatch

fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
    if s1.len() > s2.len() { s1 } else { s2 }
}

Root Cause: Return value lifetime must be tied to one of the inputs.

Key Solutions:

  1. Clarify each reference's lifetime
  2. Use named lifetimes to express relationships
  3. Prefer returning owned types

Workflow

Step 1: Who Owns the Data?

SituationOwner
Function parameterCaller owns
Function-local variableFunction owns (destroyed on return)
Struct fieldStruct instance owns
Arc<T>Multiple shared owners

Step 2: Is Borrowing Appropriate?

OperationBorrow TypeNotes
Read-only&TMultiple can coexist
Needs mutation&mut TOnly one at a time
Will original be modified during borrow?If yes, that's the issue

Step 3: Can Lifetimes Be Avoided?

Return String instead of &str
    ↓
Use owned collections instead of slices
    ↓
Use Arc/Rc for shared ownership
    ↓
Lifetimes aren't always necessary

Smart Pointer Selection

ScenarioChoiceReason
Heap-allocate single valueBox<T>Simple and direct
Single-threaded shared reference countingRc<T>Lightweight
Multi-threaded shared reference countingArc<T>Atomic operations
Need runtime borrow checkingRefCell<T>Single-threaded interior mutability
Multi-threaded interior mutabilityMutex<T> or RwLock<T>Thread-safe

Common Pitfalls

Anti-PatternProblemCorrect Approach
.clone() everywhereHides ownership issuesThink about actual ownership needs
'static for everythingToo loose and impreciseUse actual required lifetimes
Box::leak() memory leaksMemory wasteUse proper lifetime management
Fighting the borrow checkerDigging your own holeUnderstand and work with compiler design

Practical Guidance

Common Beginner Questions

1. "When should I use references vs ownership?"

  • Function parameters: use references (unless consuming)
  • Function returns: use references (if caller doesn't need ownership)
  • Storage: consider lifetime complexity

2. "How do I add lifetime annotations?"

  • Most cases: compiler can infer
  • Need explicit: structs, trait impls, methods returning references
  • Use meaningful names: 'connection, 'file

3. "Why doesn't this borrow work?"

  • Mutable borrows make original inaccessible
  • Check borrow scope ranges
  • Consider code reorganization

Error Code Quick Reference

CodeMeaningDon't SayAsk Instead
E0382Use of moved value"clone it"Who should own this data?
E0597Lifetime too short"extend lifetime"Are scope boundaries correct?
E0506Borrow not ended before mutation"end borrow first"Where should mutation occur?
E0507Move out of reference"clone before move"Why move from reference?
E0515Return non-owned data"return owned"Should caller own the data?
E0716Temporary value lifetime insufficient"bind to variable"Why is this temporary?
E0106Missing lifetime parameter"add 'a"What's the lifetime relationship?

Thinking Process

When encountering ownership issues, follow these steps:

1. What's this data's role in the domain?

  • Entity (unique identity) → owned
  • Value object (interchangeable) → clone/copy acceptable
  • Temporary computation result → consider refactor

2. Is ownership design intentional or accidental?

  • Intentional → work within constraints
  • Accidental → consider redesign

3. Fix symptom or redesign?

  • If failed 3 times → escalate to design level

Trace Up (Design Analysis)

When ownership errors persist, trace to design level:

E0382 (moved value)
    ↑ Ask: What design choice led to this ownership pattern?
    ↑ Check: Is this an entity or value object?
    ↑ Check: Are there other constraints?

Persistent E0382 → rust-resource: Should use Arc/Rc for sharing?
Persistent E0597 → rust-type-driven: Are scope boundaries correct?
E0506/E0507 → rust-mutability: Should use interior mutability?

Trace Down (Implementation)

From design decisions to implementation:

"Data needs immutable sharing"
    ↓ Multi-threaded: Arc<T>
    ↓ Single-threaded: Rc<T>

"Data needs exclusive ownership"
    ↓ Return owned value

"Data is temporary use only"
    ↓ Use references within scope

"Need to pass data between functions"
    ↓ Consider lifetimes or return owned

Review Checklist

When reviewing ownership-related code:

  • Each value has a clear owner
  • Borrows don't outlive the borrowed data
  • Mutable and immutable borrows don't overlap
  • Lifetime annotations accurately reflect data relationships
  • Smart pointer choice matches threading requirements
  • .clone() is used intentionally, not to avoid compiler errors
  • Lifetime elision is leveraged where possible
  • Complex lifetime scenarios are documented

Verification Commands

# Check compilation
cargo check

# Run tests
cargo test

# Check for common mistakes
cargo clippy -- -W clippy::clone_on_copy -W clippy::unnecessary_clone

# Verify no memory leaks in tests
cargo test --features leak-check

Common Pitfalls

1. Clone Abuse

Symptom: .clone() everywhere to satisfy compiler

Fix: Understand actual ownership requirements, use references where possible

2. Lifetime Overuse

Symptom: Complex lifetime annotations everywhere

Fix: Return owned types, use smart pointers

3. Fighting Borrow Checker

Symptom: Constantly rewriting to satisfy compiler

Fix: Step back and redesign data flow

Related Skills

  • rust-mutability - Interior mutability patterns (Cell, RefCell)
  • rust-concurrency - Send/Sync and thread safety
  • rust-unsafe - Raw pointers and manual memory management
  • rust-lifetime-complex - Advanced lifetime patterns (HRTB, GAT)
  • rust-resource - Resource management and RAII patterns
  • rust-type-driven - Type-driven design

Localized Reference

  • Chinese version: SKILL_ZH.md - 完整中文版本,包含所有内容

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.