Avoiding Clones
clone() is explicit and often expensive. Design APIs around borrows, Cow, and moved ownership so copies happen only at intentional boundaries.
Busca en todas las páginas de la documentación
clone() is explicit and often expensive. Design APIs around borrows, Cow, and moved ownership so copies happen only at intentional boundaries.
use std::borrow::Cow;
fn greet(name: Cow<'_, str>) {
println!("Hello, {name}");
}
greet(Cow::Borrowed("Ada"));
greet(Cow::Owned("Bob".into()));When to reach for this: Clippy redundant_clone fires in hot paths or review spots clone() in loops.
struct Request<'a> {
path: &'a str,
body: Cow<'a, [u8]>,
}
fn handle(req: Request<'_>) -> Status {
if req.path == "/health" {
return Status::Ok;
}
process_body(req.body.as_ref())
}What this demonstrates:
&str / &[u8] borrow when caller owns dataCow accepts borrowed or owned without forcing clone upfrontString once into struct instead of clone per useArc<str> for shared immutable strings across threads| Pattern | Use |
|---|---|
&T / &str parameters | Read-only hot paths |
Cow<'a, T> | Sometimes needs ownership |
| Move by value | Single consumer |
Arc<T> | Shared read-heavy data |
Rc<T> | Single-thread share |
async fn handler(Json(body): Json<CreateOrder>) -> impl IntoResponse {
// Json<T> owns body once; pass references into domain layer
service.create(&body).await
}Arc.Arc thinking it's cheap data clone - Arc::clone is cheap; inner String clone is not. Fix: distinguish pointer clone vs data clone.to_owned() in loop - same cost as clone(). Fix: batch or borrow.#[serde(borrow)] on &str fields when deserializing from &[u8] buffer.| Alternative | Use When | Don't Use When |
|---|---|---|
Arc<str> | Immutable shared strings | Unique mutation needed |
Pin<Box<T>> | Self-referential | Simple moved values |
&'static str | Compile-time literals | Dynamic user input |
At IO boundaries, spawning tasks needing 'static, or cheap Copy types.
Small enum discriminant; branch cost negligible vs heap clone saved.
Spawned tasks need 'static; use owned String or Arc at spawn boundary once.
cargo clippy -- -W clippy::redundant_clone and profilers.
Copy types (integers, refs) are bitwise; Clone may heap-allocate.
collect::<Vec<_>>() clones if iterating references; use into_iter() when consuming.
Use try_get to typed values; fetch &str only with compatible lifetime patterns or copy once.
Lazy plan shares; clone() on DataFrame is data copy - minimize collects.
Builder moves fields; avoid #[derive(Clone)] on large configs.
One clone() per request OK; clone per row in million-row loop needs justification.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Revisado por Chris St. John·Última actualización: 16 jul 2026