Cursor Skill

m01-ownership

CRITICAL: Use for ownership/borrow/lifetime issues. Triggers: E0382, E0597, E0506, E0507, E0515, E0716, E0106, value moved, borrowed value does not live long enough, cannot move out of, use of moved value, ownership, borrow, lifetime, 'a, 'static, move, clone, Copy, 所有权, 借用, 生命周期

LLM Mart · 0 points · 8 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download moeru-ai-auv-.agents_skills_m01-ownership-372a07b.zip · 10 KB
moeru-ai/auv 51 6 forks Apache-2.0 Updated 1d ago
Part of moeru-ai/auv — 28 skills

Install

skills CLI npx skills add https://github.com/moeru-ai/auv/tree/main/.agents/skills/m01-ownership
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install moeru-ai-auv@llmmart
Git git clone https://github.com/moeru-ai/auv.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole moeru-ai/auv collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Ownership & Lifetimes

Layer 1: Language Mechanics

Core Question

Who should own this data, and for how long?

Before fixing ownership errors, understand the data's role:

  • Is it shared or exclusive?
  • Is it short-lived or long-lived?
  • Is it transformed or just read?

Error → Design Question

Error Don't Just Say Ask Instead
E0382 "Clone it" Who should own this data?
E0597 "Extend lifetime" Is the scope boundary correct?
E0506 "End borrow first" Should mutation happen elsewhere?
E0507 "Clone before move" Why are we moving from a reference?
E0515 "Return owned" Should caller own the data?
E0716 "Bind to variable" Why is this temporary?
E0106 "Add 'a" What is the actual lifetime relationship?

Thinking Prompt

Before fixing an ownership error, ask:

  1. What is this data's domain role?

    • Entity (unique identity) → owned
    • Value Object (interchangeable) → clone/copy OK
    • Temporary (computation result) → maybe restructure
  2. Is the ownership design intentional?

    • By design → work within constraints
    • Accidental → consider redesign
  3. Fix symptom or redesign?

    • If Strike 3 (3rd attempt) → escalate to Layer 2

Trace Up ↑

When errors persist, trace to design layer:

E0382 (moved value)
    ↑ Ask: What design choice led to this ownership pattern?
    ↑ Check: m09-domain (is this Entity or Value Object?)
    ↑ Check: domain-* (what constraints apply?)
Persistent Error Trace To Question
E0382 repeated m02-resource Should use Arc/Rc for sharing?
E0597 repeated m09-domain Is scope boundary at right place?
E0506/E0507 m03-mutability Should use interior mutability?

Trace Down ↓

From design decisions to implementation:

"Data needs to be shared immutably"
    ↓ Use: Arc<T> (multi-thread) or Rc<T> (single-thread)

"Data needs exclusive ownership"
    ↓ Use: move semantics, take ownership

"Data is read-only view"
    ↓ Use: &T (immutable borrow)

Quick Reference

Pattern Ownership Cost Use When
Move Transfer Zero Caller doesn't need data
&T Borrow Zero Read-only access
&mut T Exclusive borrow Zero Need to modify
clone() Duplicate Alloc + copy Actually need a copy
Rc<T> Shared (single) Ref count Single-thread sharing
Arc<T> Shared (multi) Atomic ref count Multi-thread sharing
Cow<T> Clone-on-write Alloc if mutated Might modify

Error Code Reference

Error Cause Quick Fix
E0382 Value moved Clone, reference, or redesign ownership
E0597 Reference outlives owner Extend owner scope or restructure
E0506 Assign while borrowed End borrow before mutation
E0507 Move out of borrowed Clone or use reference
E0515 Return local reference Return owned value
E0716 Temporary dropped Bind to variable
E0106 Missing lifetime Add 'a annotation

Anti-Patterns

Anti-Pattern Why Bad Better
.clone() everywhere Hides design issues Design ownership properly
Fight borrow checker Increases complexity Work with the compiler
'static for everything Restricts flexibility Use appropriate lifetimes
Leak with Box::leak Memory leak Proper lifetime design

Related Skills

When See
Need smart pointers m02-resource
Need interior mutability m03-mutability
Data is domain entity m09-domain
Learning ownership concepts m14-mental-model
Files (auv)
  • examples
    • best-practices.md 6.5 KB
      # Ownership Best Practices
      
      ## API Design Patterns
      
      ### 1. Prefer Borrowing Over Ownership
      
      ```rust
      // BAD: takes ownership unnecessarily
      fn print_name(name: String) {
          println!("Name: {}", name);
      }
      
      // GOOD: borrows instead
      fn print_name(name: &str) {
          println!("Name: {}", name);
      }
      
      // Caller benefits:
      let name = String::from("Alice");
      print_name(&name);  // can reuse name
      print_name(&name);  // still valid
      ```
      
      ### 2. Return Owned Values from Constructors
      
      ```rust
      // GOOD: return owned value
      impl User {
          fn new(name: &str) -> Self {
              User {
                  name: name.to_string(),
              }
          }
      }
      
      // GOOD: accept Into<String> for flexibility
      impl User {
          fn new(name: impl Into<String>) -> Self {
              User {
                  name: name.into(),
              }
          }
      }
      
      // Usage:
      let u1 = User::new("Alice");        // &str
      let u2 = User::new(String::from("Bob"));  // String
      ```
      
      ### 3. Use AsRef for Generic Borrowing
      
      ```rust
      // GOOD: accepts both &str and String
      fn process<S: AsRef<str>>(input: S) {
          let s = input.as_ref();
          println!("{}", s);
      }
      
      process("literal");           // &str
      process(String::from("owned")); // String
      process(&String::from("ref")); // &String
      ```
      
      ### 4. Cow for Clone-on-Write
      
      ```rust
      use std::borrow::Cow;
      
      // Return borrowed when possible, owned when needed
      fn maybe_modify(s: &str, uppercase: bool) -> Cow<'_, str> {
          if uppercase {
              Cow::Owned(s.to_uppercase())  // allocates
          } else {
              Cow::Borrowed(s)  // zero-cost
          }
      }
      
      let input = "hello";
      let result = maybe_modify(input, false);
      // result is borrowed, no allocation
      ```
      
      ---
      
      ## Struct Design Patterns
      
      ### 1. Owned Fields vs References
      
      ```rust
      // Use owned fields for most cases
      struct User {
          name: String,
          email: String,
      }
      
      // Use references only when lifetime is clear
      struct UserView<'a> {
          name: &'a str,
          email: &'a str,
      }
      
      // Pattern: owned data + view for efficiency
      impl User {
          fn view(&self) -> UserView<'_> {
              UserView {
                  name: &self.name,
                  email: &self.email,
              }
          }
      }
      ```
      
      ### 2. Builder Pattern with Ownership
      
      ```rust
      #[derive(Default)]
      struct RequestBuilder {
          url: Option<String>,
          method: Option<String>,
          body: Option<Vec<u8>>,
      }
      
      impl RequestBuilder {
          fn new() -> Self {
              Self::default()
          }
      
          // Take self by value for chaining
          fn url(mut self, url: impl Into<String>) -> Self {
              self.url = Some(url.into());
              self
          }
      
          fn method(mut self, method: impl Into<String>) -> Self {
              self.method = Some(method.into());
              self
          }
      
          fn build(self) -> Result<Request, Error> {
              Ok(Request {
                  url: self.url.ok_or(Error::MissingUrl)?,
                  method: self.method.unwrap_or_else(|| "GET".to_string()),
                  body: self.body.unwrap_or_default(),
              })
          }
      }
      
      // Usage:
      let req = RequestBuilder::new()
          .url("https://example.com")
          .method("POST")
          .build()?;
      ```
      
      ### 3. Interior Mutability When Needed
      
      ```rust
      use std::cell::RefCell;
      use std::rc::Rc;
      
      // Shared mutable state in single-threaded context
      struct Counter {
          value: Rc<RefCell<u32>>,
      }
      
      impl Counter {
          fn new() -> Self {
              Counter {
                  value: Rc::new(RefCell::new(0)),
              }
          }
      
          fn increment(&self) {
              *self.value.borrow_mut() += 1;
          }
      
          fn get(&self) -> u32 {
              *self.value.borrow()
          }
      
          fn clone_handle(&self) -> Self {
              Counter {
                  value: Rc::clone(&self.value),
              }
          }
      }
      ```
      
      ---
      
      ## Collection Patterns
      
      ### 1. Efficient Iteration
      
      ```rust
      let items = vec![1, 2, 3, 4, 5];
      
      // Iterate by reference (no move)
      for item in &items {
          println!("{}", item);
      }
      
      // Iterate by mutable reference
      for item in &mut items.clone() {
          *item *= 2;
      }
      
      // Consume with into_iter when done
      let sum: i32 = items.into_iter().sum();
      ```
      
      ### 2. Collecting Results
      
      ```rust
      // Collect into owned collection
      let strings: Vec<String> = (0..5)
          .map(|i| format!("item_{}", i))
          .collect();
      
      // Collect references
      let refs: Vec<&str> = strings.iter().map(|s| s.as_str()).collect();
      
      // Collect with transformation
      let result: Result<Vec<i32>, _> = ["1", "2", "3"]
          .iter()
          .map(|s| s.parse::<i32>())
          .collect();
      ```
      
      ### 3. Entry API for Maps
      
      ```rust
      use std::collections::HashMap;
      
      let mut map: HashMap<String, Vec<i32>> = HashMap::new();
      
      // Efficient: don't search twice
      map.entry("key".to_string())
         .or_insert_with(Vec::new)
         .push(42);
      
      // With entry modification
      map.entry("key".to_string())
         .and_modify(|v| v.push(43))
         .or_insert_with(|| vec![43]);
      ```
      
      ---
      
      ## Error Handling with Ownership
      
      ### 1. Preserve Context in Errors
      
      ```rust
      use std::error::Error;
      use std::fmt;
      
      #[derive(Debug)]
      struct ParseError {
          input: String,  // owns the problematic input
          message: String,
      }
      
      impl fmt::Display for ParseError {
          fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
              write!(f, "Failed to parse '{}': {}", self.input, self.message)
          }
      }
      
      fn parse(input: &str) -> Result<i32, ParseError> {
          input.parse().map_err(|_| ParseError {
              input: input.to_string(),  // clone for error context
              message: "not a valid integer".to_string(),
          })
      }
      ```
      
      ### 2. Ownership in Result Chains
      
      ```rust
      fn process_data(path: &str) -> Result<ProcessedData, Error> {
          let content = std::fs::read_to_string(path)?;  // owned String
          let parsed = parse_content(&content)?;          // borrow
          let processed = transform(parsed)?;             // ownership moves
          Ok(processed)                                   // return owned
      }
      ```
      
      ---
      
      ## Performance Considerations
      
      ### 1. Avoid Unnecessary Clones
      
      ```rust
      // BAD: cloning just to compare
      fn contains_item(items: &[String], target: &str) -> bool {
          items.iter().any(|s| s.clone() == target)  // unnecessary clone
      }
      
      // GOOD: compare references
      fn contains_item(items: &[String], target: &str) -> bool {
          items.iter().any(|s| s == target)  // String implements PartialEq<str>
      }
      ```
      
      ### 2. Use Slices for Flexibility
      
      ```rust
      // BAD: requires Vec
      fn sum(numbers: &Vec<i32>) -> i32 {
          numbers.iter().sum()
      }
      
      // GOOD: accepts any slice
      fn sum(numbers: &[i32]) -> i32 {
          numbers.iter().sum()
      }
      
      // Now works with:
      sum(&vec![1, 2, 3]);     // Vec
      sum(&[1, 2, 3]);         // array
      sum(&array[1..3]);       // slice
      ```
      
      ### 3. In-Place Mutation
      
      ```rust
      // BAD: allocates new String
      fn make_uppercase(s: &str) -> String {
          s.to_uppercase()
      }
      
      // GOOD when you own the data: mutate in place
      fn make_uppercase(mut s: String) -> String {
          s.make_ascii_uppercase();  // in-place for ASCII
          s
      }
      ```
      
  • patterns
    • common-errors.md 4.9 KB
      # Common Ownership Errors & Fixes
      
      ## E0382: Use of Moved Value
      
      ### Error Pattern
      ```rust
      let s = String::from("hello");
      let s2 = s;          // s moved here
      println!("{}", s);   // ERROR: value borrowed after move
      ```
      
      ### Fix Options
      
      **Option 1: Clone (if ownership not needed)**
      ```rust
      let s = String::from("hello");
      let s2 = s.clone();  // s is cloned
      println!("{}", s);   // OK: s still valid
      ```
      
      **Option 2: Borrow (if modification not needed)**
      ```rust
      let s = String::from("hello");
      let s2 = &s;         // borrow, not move
      println!("{}", s);   // OK
      println!("{}", s2);  // OK
      ```
      
      **Option 3: Use Rc/Arc (for shared ownership)**
      ```rust
      use std::rc::Rc;
      let s = Rc::new(String::from("hello"));
      let s2 = Rc::clone(&s);  // shared ownership
      println!("{}", s);       // OK
      println!("{}", s2);      // OK
      ```
      
      ---
      
      ## E0597: Borrowed Value Does Not Live Long Enough
      
      ### Error Pattern
      ```rust
      fn get_str() -> &str {
          let s = String::from("hello");
          &s  // ERROR: s dropped here, but reference returned
      }
      ```
      
      ### Fix Options
      
      **Option 1: Return owned value**
      ```rust
      fn get_str() -> String {
          String::from("hello")  // return owned value
      }
      ```
      
      **Option 2: Use 'static lifetime**
      ```rust
      fn get_str() -> &'static str {
          "hello"  // string literal has 'static lifetime
      }
      ```
      
      **Option 3: Accept reference parameter**
      ```rust
      fn get_str<'a>(s: &'a str) -> &'a str {
          s  // return reference with same lifetime as input
      }
      ```
      
      ---
      
      ## E0499: Cannot Borrow as Mutable More Than Once
      
      ### Error Pattern
      ```rust
      let mut s = String::from("hello");
      let r1 = &mut s;
      let r2 = &mut s;  // ERROR: second mutable borrow
      println!("{}, {}", r1, r2);
      ```
      
      ### Fix Options
      
      **Option 1: Sequential borrows**
      ```rust
      let mut s = String::from("hello");
      {
          let r1 = &mut s;
          r1.push_str(" world");
      }  // r1 goes out of scope
      let r2 = &mut s;  // OK: r1 no longer exists
      ```
      
      **Option 2: Use RefCell for interior mutability**
      ```rust
      use std::cell::RefCell;
      let s = RefCell::new(String::from("hello"));
      let mut r1 = s.borrow_mut();
      // drop r1 before borrowing again
      drop(r1);
      let mut r2 = s.borrow_mut();
      ```
      
      ---
      
      ## E0502: Cannot Borrow as Mutable While Immutable Borrow Exists
      
      ### Error Pattern
      ```rust
      let mut v = vec![1, 2, 3];
      let first = &v[0];      // immutable borrow
      v.push(4);              // ERROR: mutable borrow while immutable exists
      println!("{}", first);
      ```
      
      ### Fix Options
      
      **Option 1: Finish using immutable borrow first**
      ```rust
      let mut v = vec![1, 2, 3];
      let first = v[0];       // copy value, not borrow
      v.push(4);              // OK
      println!("{}", first);  // OK: using copied value
      ```
      
      **Option 2: Clone before mutating**
      ```rust
      let mut v = vec![1, 2, 3];
      let first = v[0].clone();  // if T: Clone
      v.push(4);
      println!("{}", first);
      ```
      
      ---
      
      ## E0507: Cannot Move Out of Borrowed Content
      
      ### Error Pattern
      ```rust
      fn take_string(s: &String) {
          let moved = *s;  // ERROR: cannot move out of borrowed content
      }
      ```
      
      ### Fix Options
      
      **Option 1: Clone**
      ```rust
      fn take_string(s: &String) {
          let cloned = s.clone();
      }
      ```
      
      **Option 2: Take ownership in function signature**
      ```rust
      fn take_string(s: String) {  // take ownership
          let moved = s;
      }
      ```
      
      **Option 3: Use mem::take for Option/Default types**
      ```rust
      fn take_from_option(opt: &mut Option<String>) -> Option<String> {
          std::mem::take(opt)  // replaces with None, returns owned value
      }
      ```
      
      ---
      
      ## E0515: Return Local Reference
      
      ### Error Pattern
      ```rust
      fn create_string() -> &String {
          let s = String::from("hello");
          &s  // ERROR: cannot return reference to local variable
      }
      ```
      
      ### Fix Options
      
      **Option 1: Return owned value**
      ```rust
      fn create_string() -> String {
          String::from("hello")
      }
      ```
      
      **Option 2: Use static/const**
      ```rust
      fn get_static_str() -> &'static str {
          "hello"
      }
      ```
      
      ---
      
      ## E0716: Temporary Value Dropped While Borrowed
      
      ### Error Pattern
      ```rust
      let r: &str = &String::from("hello");  // ERROR: temporary dropped
      println!("{}", r);
      ```
      
      ### Fix Options
      
      **Option 1: Bind to variable first**
      ```rust
      let s = String::from("hello");
      let r: &str = &s;
      println!("{}", r);
      ```
      
      **Option 2: Use let binding with reference**
      ```rust
      let r: &str = {
          let s = String::from("hello");
          // s.as_str()  // ERROR: still temporary
          Box::leak(s.into_boxed_str())  // extreme: leak for 'static
      };
      ```
      
      ---
      
      ## Pattern: Loop Ownership Issues
      
      ### Error Pattern
      ```rust
      let strings = vec![String::from("a"), String::from("b")];
      for s in strings {
          println!("{}", s);
      }
      // ERROR: strings moved into loop
      println!("{:?}", strings);
      ```
      
      ### Fix Options
      
      **Option 1: Iterate by reference**
      ```rust
      let strings = vec![String::from("a"), String::from("b")];
      for s in &strings {
          println!("{}", s);
      }
      println!("{:?}", strings);  // OK
      ```
      
      **Option 2: Use iter()**
      ```rust
      for s in strings.iter() {
          println!("{}", s);
      }
      ```
      
      **Option 3: Clone if needed**
      ```rust
      for s in strings.clone() {
          // consumes cloned vec
      }
      println!("{:?}", strings);  // original still available
      ```
      
    • lifetime-patterns.md 4.4 KB
      # Lifetime Patterns
      
      ## Basic Lifetime Annotation
      
      ### When Required
      ```rust
      // ERROR: missing lifetime specifier
      fn longest(x: &str, y: &str) -> &str {
          if x.len() > y.len() { x } else { y }
      }
      
      // FIX: explicit lifetime
      fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
          if x.len() > y.len() { x } else { y }
      }
      ```
      
      ### Lifetime Elision Rules
      1. Each input reference gets its own lifetime
      2. If one input lifetime, output uses same
      3. If `&self` or `&mut self`, output uses self's lifetime
      
      ```rust
      // These are equivalent (elision applies):
      fn first_word(s: &str) -> &str { ... }
      fn first_word<'a>(s: &'a str) -> &'a str { ... }
      
      // Method with self (elision applies):
      impl MyStruct {
          fn get_ref(&self) -> &str { ... }
          // Equivalent to:
          fn get_ref<'a>(&'a self) -> &'a str { ... }
      }
      ```
      
      ---
      
      ## Struct Lifetimes
      
      ### Struct Holding References
      ```rust
      // Struct must declare lifetime for references
      struct Excerpt<'a> {
          part: &'a str,
      }
      
      impl<'a> Excerpt<'a> {
          fn level(&self) -> i32 { 3 }
      
          // Return reference tied to self's lifetime
          fn get_part(&self) -> &str {
              self.part
          }
      }
      ```
      
      ### Multiple Lifetimes in Struct
      ```rust
      struct Multi<'a, 'b> {
          x: &'a str,
          y: &'b str,
      }
      
      // Use when references may have different lifetimes
      fn make_multi<'a, 'b>(x: &'a str, y: &'b str) -> Multi<'a, 'b> {
          Multi { x, y }
      }
      ```
      
      ---
      
      ## 'static Lifetime
      
      ### When to Use
      ```rust
      // String literals are 'static
      let s: &'static str = "hello";
      
      // Owned data can be leaked to 'static
      let leaked: &'static str = Box::leak(String::from("hello").into_boxed_str());
      
      // Thread spawn requires 'static or move
      std::thread::spawn(move || {
          // closure owns data, satisfies 'static
      });
      ```
      
      ### Avoid Overusing 'static
      ```rust
      // BAD: requires 'static unnecessarily
      fn process(s: &'static str) { ... }
      
      // GOOD: use generic lifetime
      fn process<'a>(s: &'a str) { ... }
      // or
      fn process(s: &str) { ... }  // lifetime elision
      ```
      
      ---
      
      ## Higher-Ranked Trait Bounds (HRTB)
      
      ### for<'a> Syntax
      ```rust
      // Function that works with any lifetime
      fn apply_to_ref<F>(f: F)
      where
          F: for<'a> Fn(&'a str) -> &'a str,
      {
          let s = String::from("hello");
          let result = f(&s);
          println!("{}", result);
      }
      ```
      
      ### Common Use: Closure Bounds
      ```rust
      // Closure that borrows any lifetime
      fn filter_refs<F>(items: &[&str], pred: F) -> Vec<&str>
      where
          F: for<'a> Fn(&'a str) -> bool,
      {
          items.iter().copied().filter(|s| pred(s)).collect()
      }
      ```
      
      ---
      
      ## Lifetime Bounds
      
      ### 'a: 'b (Outlives)
      ```rust
      // 'a must live at least as long as 'b
      fn coerce<'a, 'b>(x: &'a str) -> &'b str
      where
          'a: 'b,
      {
          x
      }
      ```
      
      ### T: 'a (Type Outlives Lifetime)
      ```rust
      // T must live at least as long as 'a
      struct Wrapper<'a, T: 'a> {
          value: &'a T,
      }
      
      // Common pattern with trait objects
      fn use_trait<'a, T: MyTrait + 'a>(t: &'a T) { ... }
      ```
      
      ---
      
      ## Common Lifetime Mistakes
      
      ### Mistake 1: Returning Reference to Local
      ```rust
      // WRONG
      fn dangle() -> &String {
          let s = String::from("hello");
          &s  // s dropped, reference invalid
      }
      
      // RIGHT
      fn no_dangle() -> String {
          String::from("hello")
      }
      ```
      
      ### Mistake 2: Conflicting Lifetimes
      ```rust
      // WRONG: might return reference to y which has shorter lifetime
      fn wrong<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
          y  // ERROR: 'b might not live as long as 'a
      }
      
      // RIGHT: use same lifetime or add bound
      fn right<'a>(x: &'a str, y: &'a str) -> &'a str {
          y  // OK: both have lifetime 'a
      }
      ```
      
      ### Mistake 3: Struct Outlives Reference
      ```rust
      // WRONG: s might outlive the string it references
      let r;
      {
          let s = String::from("hello");
          r = Excerpt { part: &s };  // ERROR
      }
      println!("{}", r.part);  // s already dropped
      
      // RIGHT: ensure source outlives struct
      let s = String::from("hello");
      let r = Excerpt { part: &s };
      println!("{}", r.part);  // OK: s still in scope
      ```
      
      ---
      
      ## Subtyping and Variance
      
      ### Covariance
      ```rust
      // &'a T is covariant in 'a
      // Can use &'long where &'short expected
      fn example<'short, 'long: 'short>(long_ref: &'long str) {
          let short_ref: &'short str = long_ref;  // OK: covariance
      }
      ```
      
      ### Invariance
      ```rust
      // &'a mut T is invariant in 'a
      fn example<'a, 'b>(x: &'a mut &'b str, y: &'b str) {
          *x = y;  // ERROR if 'a and 'b are different
      }
      ```
      
      ### Practical Impact
      ```rust
      // This works due to covariance
      fn accept_any<'a>(s: &'a str) { ... }
      
      let s = String::from("hello");
      let long_lived: &str = &s;
      accept_any(long_lived);  // 'long coerces to 'short
      ```
      
  • comparison.md 5.6 KB
    # Ownership: Comparison with Other Languages
    
    ## Rust vs C++
    
    ### Memory Management
    
    | Aspect | Rust | C++ |
    |--------|------|-----|
    | Default | Move semantics | Copy semantics (pre-C++11) |
    | Move | `let b = a;` (a invalidated) | `auto b = std::move(a);` (a valid but unspecified) |
    | Copy | `let b = a.clone();` | `auto b = a;` |
    | Safety | Compile-time enforcement | Runtime responsibility |
    
    ### Rust Move vs C++ Move
    
    ```rust
    // Rust: after move, 'a' is INVALID
    let a = String::from("hello");
    let b = a;  // a moved
    // println!("{}", a);  // COMPILE ERROR
    
    // Equivalent in C++:
    // std::string a = "hello";
    // std::string b = std::move(a);
    // std::cout << a;  // UNDEFINED (compiles but buggy)
    ```
    
    ### Smart Pointers
    
    | Rust | C++ | Purpose |
    |------|-----|---------|
    | `Box<T>` | `std::unique_ptr<T>` | Unique ownership |
    | `Rc<T>` | `std::shared_ptr<T>` | Shared ownership |
    | `Arc<T>` | `std::shared_ptr<T>` + atomic | Thread-safe shared |
    | `RefCell<T>` | (manual runtime checks) | Interior mutability |
    
    ---
    
    ## Rust vs Go
    
    ### Memory Model
    
    | Aspect | Rust | Go |
    |--------|------|-----|
    | Memory | Stack + heap, explicit | GC manages all |
    | Ownership | Enforced at compile-time | None (GC handles) |
    | Null | `Option<T>` | `nil` for pointers |
    | Concurrency | `Send`/`Sync` traits | Channels (less strict) |
    
    ### Sharing Data
    
    ```rust
    // Rust: explicit about sharing
    use std::sync::Arc;
    let data = Arc::new(vec![1, 2, 3]);
    let data_clone = Arc::clone(&data);
    std::thread::spawn(move || {
        println!("{:?}", data_clone);
    });
    
    // Go: implicit sharing
    // data := []int{1, 2, 3}
    // go func() {
    //     fmt.Println(data)  // potential race condition
    // }()
    ```
    
    ### Why No GC in Rust
    
    1. **Deterministic destruction**: Resources freed exactly when scope ends
    2. **Zero-cost**: No GC pauses or overhead
    3. **Embeddable**: Works in OS kernels, embedded systems
    4. **Predictable latency**: Critical for real-time systems
    
    ---
    
    ## Rust vs Java/C#
    
    ### Reference Semantics
    
    | Aspect | Rust | Java/C# |
    |--------|------|---------|
    | Objects | Owned by default | Reference by default |
    | Null | `Option<T>` | `null` (nullable) |
    | Immutability | Default | Must use `final`/`readonly` |
    | Copy | Explicit `.clone()` | Reference copy (shallow) |
    
    ### Comparison
    
    ```rust
    // Rust: clear ownership
    fn process(data: Vec<i32>) {  // takes ownership
        // data is ours, will be freed at end
    }
    
    let numbers = vec![1, 2, 3];
    process(numbers);
    // numbers is invalid here
    
    // Java: ambiguous ownership
    // void process(List<Integer> data) {
    //     // Who owns data? Caller? Callee? Both?
    //     // Can caller still use it?
    // }
    ```
    
    ---
    
    ## Rust vs Python
    
    ### Memory Model
    
    | Aspect | Rust | Python |
    |--------|------|--------|
    | Typing | Static, compile-time | Dynamic, runtime |
    | Memory | Ownership-based | Reference counting + GC |
    | Mutability | Default immutable | Default mutable |
    | Performance | Native, zero-cost | Interpreted, higher overhead |
    
    ### Common Pattern Translation
    
    ```rust
    // Rust: borrowing iteration
    let items = vec!["a", "b", "c"];
    for item in &items {
        println!("{}", item);
    }
    // items still usable
    
    // Python: iteration doesn't consume
    // items = ["a", "b", "c"]
    // for item in items:
    //     print(item)
    // items still usable (different reason - ref counting)
    ```
    
    ---
    
    ## Unique Rust Concepts
    
    ### Concepts Other Languages Lack
    
    1. **Borrow Checker**: No other mainstream language has compile-time borrow checking
    2. **Lifetimes**: Explicit annotation of reference validity
    3. **Move by Default**: Values move, not copy
    4. **No Null**: `Option<T>` instead of null pointers
    5. **Affine Types**: Values can be used at most once
    
    ### Learning Curve Areas
    
    | Concept | Coming From | Key Insight |
    |---------|-------------|-------------|
    | Ownership | GC languages | Think about who "owns" data |
    | Borrowing | C/C++ | Like references but checked |
    | Lifetimes | Any | Explicit scope of validity |
    | Move | C++ | Move is default, not copy |
    
    ---
    
    ## Mental Model Shifts
    
    ### From GC Languages (Java, Go, Python)
    
    ```
    Before: "Memory just works, GC handles it"
    After:  "I explicitly decide who owns data and when it's freed"
    ```
    
    Key shifts:
    - Think about ownership at design time
    - Returning references requires lifetime thinking
    - No more `null` - use `Option<T>`
    
    ### From C/C++
    
    ```
    Before: "I manually manage memory and hope I get it right"
    After:  "Compiler enforces correctness, I fight the borrow checker"
    ```
    
    Key shifts:
    - Trust the compiler's errors
    - Move is the default (unlike C++ copy)
    - Smart pointers are idiomatic, not overhead
    
    ### From Functional Languages (Haskell, ML)
    
    ```
    Before: "Everything is immutable, copying is fine"
    After:  "Mutability is explicit, ownership prevents aliasing"
    ```
    
    Key shifts:
    - Mutability is safe because of ownership rules
    - No persistent data structures needed (usually)
    - Performance characteristics are explicit
    
    ---
    
    ## Performance Trade-offs
    
    | Language | Memory Overhead | Latency | Throughput |
    |----------|-----------------|---------|------------|
    | Rust | Minimal (no GC) | Predictable | Excellent |
    | C++ | Minimal | Predictable | Excellent |
    | Go | GC overhead | GC pauses | Good |
    | Java | GC overhead | GC pauses | Good |
    | Python | High (ref counting + GC) | Variable | Lower |
    
    ### When Rust Ownership Wins
    
    1. **Real-time systems**: No GC pauses
    2. **Embedded**: No runtime overhead
    3. **High-performance**: Zero-cost abstractions
    4. **Concurrent**: Data races prevented at compile time
    
    ### When GC Might Be Preferable
    
    1. **Rapid prototyping**: Less mental overhead
    2. **Complex object graphs**: Cycles are tricky in Rust
    3. **GUI applications**: Object lifetimes are dynamic
    4. **Small programs**: Overhead doesn't matter
    
  • SKILL.md 4.1 KB
    ---
    name: m01-ownership
    description: "CRITICAL: Use for ownership/borrow/lifetime issues. Triggers: E0382, E0597, E0506, E0507, E0515, E0716, E0106, value moved, borrowed value does not live long enough, cannot move out of, use of moved value, ownership, borrow, lifetime, 'a, 'static, move, clone, Copy, 所有权, 借用, 生命周期"
    user-invocable: false
    ---
    
    # Ownership & Lifetimes
    
    > **Layer 1: Language Mechanics**
    
    ## Core Question
    
    **Who should own this data, and for how long?**
    
    Before fixing ownership errors, understand the data's role:
    - Is it shared or exclusive?
    - Is it short-lived or long-lived?
    - Is it transformed or just read?
    
    ---
    
    ## Error → Design Question
    
    | Error | Don't Just Say | Ask Instead |
    |-------|----------------|-------------|
    | E0382 | "Clone it" | Who should own this data? |
    | E0597 | "Extend lifetime" | Is the scope boundary correct? |
    | E0506 | "End borrow first" | Should mutation happen elsewhere? |
    | E0507 | "Clone before move" | Why are we moving from a reference? |
    | E0515 | "Return owned" | Should caller own the data? |
    | E0716 | "Bind to variable" | Why is this temporary? |
    | E0106 | "Add 'a" | What is the actual lifetime relationship? |
    
    ---
    
    ## Thinking Prompt
    
    Before fixing an ownership error, ask:
    
    1. **What is this data's domain role?**
       - Entity (unique identity) → owned
       - Value Object (interchangeable) → clone/copy OK
       - Temporary (computation result) → maybe restructure
    
    2. **Is the ownership design intentional?**
       - By design → work within constraints
       - Accidental → consider redesign
    
    3. **Fix symptom or redesign?**
       - If Strike 3 (3rd attempt) → escalate to Layer 2
    
    ---
    
    ## Trace Up ↑
    
    When errors persist, trace to design layer:
    
    ```
    E0382 (moved value)
        ↑ Ask: What design choice led to this ownership pattern?
        ↑ Check: m09-domain (is this Entity or Value Object?)
        ↑ Check: domain-* (what constraints apply?)
    ```
    
    | Persistent Error | Trace To | Question |
    |-----------------|----------|----------|
    | E0382 repeated | m02-resource | Should use Arc/Rc for sharing? |
    | E0597 repeated | m09-domain | Is scope boundary at right place? |
    | E0506/E0507 | m03-mutability | Should use interior mutability? |
    
    ---
    
    ## Trace Down ↓
    
    From design decisions to implementation:
    
    ```
    "Data needs to be shared immutably"
        ↓ Use: Arc<T> (multi-thread) or Rc<T> (single-thread)
    
    "Data needs exclusive ownership"
        ↓ Use: move semantics, take ownership
    
    "Data is read-only view"
        ↓ Use: &T (immutable borrow)
    ```
    
    ---
    
    ## Quick Reference
    
    | Pattern | Ownership | Cost | Use When |
    |---------|-----------|------|----------|
    | Move | Transfer | Zero | Caller doesn't need data |
    | `&T` | Borrow | Zero | Read-only access |
    | `&mut T` | Exclusive borrow | Zero | Need to modify |
    | `clone()` | Duplicate | Alloc + copy | Actually need a copy |
    | `Rc<T>` | Shared (single) | Ref count | Single-thread sharing |
    | `Arc<T>` | Shared (multi) | Atomic ref count | Multi-thread sharing |
    | `Cow<T>` | Clone-on-write | Alloc if mutated | Might modify |
    
    ## Error Code Reference
    
    | Error | Cause | Quick Fix |
    |-------|-------|-----------|
    | E0382 | Value moved | Clone, reference, or redesign ownership |
    | E0597 | Reference outlives owner | Extend owner scope or restructure |
    | E0506 | Assign while borrowed | End borrow before mutation |
    | E0507 | Move out of borrowed | Clone or use reference |
    | E0515 | Return local reference | Return owned value |
    | E0716 | Temporary dropped | Bind to variable |
    | E0106 | Missing lifetime | Add `'a` annotation |
    
    ---
    
    ## Anti-Patterns
    
    | Anti-Pattern | Why Bad | Better |
    |--------------|---------|--------|
    | `.clone()` everywhere | Hides design issues | Design ownership properly |
    | Fight borrow checker | Increases complexity | Work with the compiler |
    | `'static` for everything | Restricts flexibility | Use appropriate lifetimes |
    | Leak with `Box::leak` | Memory leak | Proper lifetime design |
    
    ---
    
    ## Related Skills
    
    | When | See |
    |------|-----|
    | Need smart pointers | m02-resource |
    | Need interior mutability | m03-mutability |
    | Data is domain entity | m09-domain |
    | Learning ownership concepts | m14-mental-model |
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related