Cow (Clone-on-Write) is a smart pointer that allows you to borrow data cheaply but provides a fallback to owning and mutating that data only when necessary. It is ideal for functions that accept either borrowed or owned data, letting you avoid unnecessary allocations when the input is already borrowed and only cloning if you need to modify it.
You typically use Cow when writing a function that takes &str or String but might need to return a modified version. By using Cow<'a, str>, you can accept a reference without copying, but if the logic requires mutation, you can clone the string into an owned String at that specific point.
Here is a practical example of a function that normalizes text. If the input is already lowercase, it returns a reference to the original data (zero allocation). If it contains uppercase letters, it clones the data, modifies it, and returns the owned string.
use std::borrow::Cow;
fn normalize_text(input: &str) -> Cow<'_, str> {
if input.chars().all(|c| c.is_lowercase() || c.is_whitespace()) {
// No mutation needed; return a reference to the original data
Cow::Borrowed(input)
} else {
// Mutation needed; clone to owned String, modify, and return
let mut s = String::from(input);
s.make_ascii_lowercase();
Cow::Owned(s)
}
}
fn main() {
let borrowed = normalize_text("hello world");
let owned = normalize_text("Hello World");
println!("Borrowed: {}", borrowed); // Prints: hello world
println!("Owned: {}", owned); // Prints: hello world
}
You can also use Cow with collections like Vec. This is useful when processing lists where most inputs are already in the correct format, but some require transformation.
use std::borrow::Cow;
fn process_items<'a>(items: Cow<'a, [i32]>) -> Cow<'a, [i32]> {
// Check if any item is negative
if items.iter().any(|&x| x < 0) {
// Clone to owned Vec to allow mutation
let mut owned = items.into_owned();
for x in owned.iter_mut() {
if *x < 0 { *x = 0; }
}
Cow::Owned(owned)
} else {
// No mutation needed
items
}
}
The key benefit is performance optimization without sacrificing API flexibility. You avoid the cost of cloning when it isn't needed, but you retain the ability to mutate data when the logic demands it. Just remember that Cow implements Deref, so you can use it like a reference in most contexts, but you must call .into_owned() if you need to take ownership of the data explicitly.