rust
✓Verified·Scanned 2/18/2026
Write idiomatic Rust avoiding ownership pitfalls, lifetime confusion, and common borrow checker battles.
from clawhub.ai·v24e0359·4.1 KB·0 installs
Scanned from 1.0.0 at 24e0359 · Transparency log ↗
$ vett add clawhub.ai/ivangdavila/rust
Ownership Traps
- Variable moved after use — clone explicitly or borrow with
& for item in vecmoves vec — use&vecor.iter()to borrow- Struct field access moves field if not Copy — destructure or clone
- Closure captures by move with
move ||— needed for threads and 'static Stringmoved into function — pass&strfor read-only access
Borrowing Battles
- Can't have mutable and immutable borrow simultaneously — restructure code or use interior mutability
- Borrow lasts until last use (NLL) — not until scope end in modern Rust
- Returning reference to local fails — return owned value or use lifetime parameter
- Mutable borrow through
&mut selfblocks all other access — split struct or useRefCell
Lifetime Gotchas
- Missing lifetime annotation — compiler usually infers, explicit when multiple references
'staticmeans "can live forever", not "lives forever" —Stringis 'static,&strmay not be- Struct holding reference needs lifetime parameter —
struct Foo<'a> { bar: &'a str } - Function returning reference must tie to input lifetime —
fn get<'a>(s: &'a str) -> &'a str
String Confusion
Stringis owned,&stris borrowed slice — convert with.as_str()orString::from()- Indexing
s[0]fails — UTF-8 variable width, use.chars().nth(0)or.bytes() - Concatenation:
s1 + &s2moves s1 — useformat!("{}{}", s1, s2)to keep both .len()returns bytes, not characters — use.chars().count()for char count
Error Handling
unwrap()panics on None/Err — use?operator ormatchin production?requires function returns Result/Option — can't use in main without-> Result<()>- Converting errors:
map_err()orFromtrait implementation expect("msg")better thanunwrap()— shows context on panicOptionandResultdon't mix — use.ok()or.ok_or()to convert
Pattern Matching
- Match must be exhaustive — use
_wildcard for remaining cases if letfor single pattern — avoids verbose match for one case- Guard conditions:
match x { n if n > 0 => ... }— guards don't create bindings @bindings:Some(val @ 1..=5)— binds matched value to namerefkeyword in patterns to borrow — often unnecessary with match ergonomics
Iterator Gotchas
.iter()borrows,.into_iter()moves,.iter_mut()borrows mutably.collect()needs type annotation —collect::<Vec<_>>()or let binding with type- Iterators are lazy — nothing happens until consumed
.map()returns iterator, not collection — chain with.collect()- Modifying while iterating impossible — collect indices first, then modify
Type System
- Orphan rule: can't impl external trait on external type — newtype pattern workaround
- Trait objects
dyn Traithave runtime cost — generics monomorphize for performance Box<dyn Trait>for heap-allocated trait object —&dyn Traitfor borrowed- Associated types vs generics: use associated when one impl per type
Selfvsself: type vs value —Self::new()vs&self
Concurrency
- Data shared between threads needs
SendandSync— most types are,Rcis not - Use
Arcfor shared ownership across threads —Rcis single-threaded only Mutex<T>for mutable shared state — lock returns guard, auto-unlocks on dropRwLockallows multiple readers or one writer — deadlock if reader tries to write- Async functions return
Future— must be awaited or spawned
Memory Patterns
Box<T>for heap allocation — also needed for recursive typesRc<T>for shared ownership (single-thread) —Arc<T>for multi-threadRefCell<T>for interior mutability — runtime borrow checking, panics on violationCell<T>for Copy types interior mutability — no borrow, just get/set- Avoid
Rc<RefCell<T>>spaghetti — rethink ownership structure