rust.clone_in_loop
Performance
Medium
Detects expensive .clone() calls inside loops.
Why It Matters
Section titled “Why It Matters”Cloning in loops multiplies allocation costs:
- Memory pressure — N iterations = N allocations
- CPU overhead — Deep structures take time to clone
- Hidden cost — Clone looks innocent but can be expensive
- Scales with input — Performance degrades with larger data
Example
Section titled “Example”// ❌ Beforefn process_all(config: Config, items: &[Item]) { for item in items { process_item(item, config.clone()); // Clones on every iteration }}If items has 10,000 elements and Config is large, that’s 10,000 expensive clones.
// ✅ Afterfn process_all(config: &Config, items: &[Item]) { for item in items { process_item(item, config); // Just borrows }}
// Or if ownership is needed, use Arcfn process_all(config: Arc<Config>, items: &[Item]) { for item in items { process_item(item, Arc::clone(&config)); // Cheap ref count bump }}What Unfault Detects
Section titled “What Unfault Detects”.clone()calls on non-Copy types inside loops- Clone inside closures passed to iterators
- Repeated cloning of the same variable
Auto-Fix
Section titled “Auto-Fix”Unfault suggests borrowing or Arc wrapping based on usage patterns.
Cheap vs Expensive Clone
Section titled “Cheap vs Expensive Clone”// Cheap clones (optimized or Copy)Arc::clone(&arc) // Just ref countRc::clone(&rc) // Just ref counti32::clone(&num) // Copy type
// Expensive clones (avoid in loops)String::clone(&s) // Full heap allocationVec::clone(&v) // Full heap allocation + element clonesHashMap::clone(&m) // Full allocation + all key/value clonesAlternative Patterns
Section titled “Alternative Patterns”// Use referencesfn process(data: &Data) { }
// Use Arc for shared ownershiplet shared = Arc::new(expensive_data);for item in items { let data = Arc::clone(&shared); spawn(async move { use_data(item, data) });}
// Clone once before looplet template = expensive_template.clone();for item in items { let mut copy = template.clone(); // Still clones, but template is prepared}
// Use Cow for conditional cloninguse std::borrow::Cow;fn process(data: Cow<'_, Data>) { // Only clones if mutation needed}