Rust Guide > Documentation > Collections > Cow

Introduction

The Cow (Clone on Write) class in Rust is an enum provided by the standard library that allows efficient handling of data that may either be owned or borrowed. It enables a way to delay the cloning of data until it is actually modified, which can improve performance by avoiding unnecessary copies. The Cow enum has two variants: Borrowed and Owned.

Using Cow

The Cow class can be used to handle data that can either be borrowed or owned, and only clone the data when it is modified. Here is a basic example:

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Borrowed(&s);

    match cow {
        Cow::Borrowed(borrowed) => println!("Borrowed: {}", borrowed),
        Cow::Owned(owned) => println!("Owned: {}", owned),
    }
}
// Output: Borrowed: hello

Key Methods

Below are some of the key methods exposed by the Cow class:

new

Creates a new Cow from a borrowed reference.

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow = Cow::new(&s);
    println!("Cow created with value: {}", cow);
}
// Output: Cow created with value: hello

into_owned

Converts the Cow into an owned value, cloning the data if necessary.

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Borrowed(&s);
    let owned = cow.into_owned();
    println!("Owned value: {}", owned);
}
// Output: Owned value: hello

to_mut

Ensures that the Cow contains an owned value, cloning the data if necessary, and returns a mutable reference to the contained data.

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let mut cow: Cow<str> = Cow::Borrowed(&s);
    cow.to_mut().push_str(" world");
    println!("Modified value: {}", cow);
}
// Output: Modified value: hello world

is_borrowed

Returns true if the Cow is in the Borrowed variant.

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Borrowed(&s);
    println!("Is borrowed: {}", cow.is_borrowed());
}
// Output: Is borrowed: true

is_owned

Returns true if the Cow is in the Owned variant.

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Owned(s.clone());
    println!("Is owned: {}", cow.is_owned());
}
// Output: Is owned: true

Example Usage

Example 1: Basic Usage

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Borrowed(&s);

    match cow {
        Cow::Borrowed(borrowed) => println!("Borrowed: {}", borrowed),
        Cow::Owned(owned) => println!("Owned: {}", owned),
    }
}
// Output: Borrowed: hello

Example 2: Creating a Cow from a Borrowed Reference

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow = Cow::new(&s);
    println!("Cow created with value: {}", cow);
}
// Output: Cow created with value: hello

Example 3: Converting Cow to Owned

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Borrowed(&s);
    let owned = cow.into_owned();
    println!("Owned value: {}", owned);
}
// Output: Owned value: hello

Example 4: Modifying Cow using to_mut

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let mut cow: Cow<str> = Cow::Borrowed(&s);
    cow.to_mut().push_str(" world");
    println!("Modified value: {}", cow);
}
// Output: Modified value: hello world

Example 5: Checking if Cow is Borrowed or Owned

use std::borrow::Cow;

fn main() {
    let s = "hello".to_string();
    let cow: Cow<str> = Cow::Borrowed(&s);
    println!("Is borrowed: {}", cow.is_borrowed());

    let cow_owned: Cow<str> = Cow::Owned(s.clone());
    println!("Is owned: {}", cow_owned.is_owned());
}
// Output:
// Is borrowed: true
// Is owned: true

Considerations

  • Cow is particularly useful when you need to work with data that is mostly read-only but occasionally modified. It avoids the cost of cloning until a mutation occurs.
  • When using Cow with large data structures, be mindful of the potential performance impact when a clone occurs.
  • Cow can be used with both str and [T] types, making it versatile for handling both strings and slices.

See Also

  • Arc - An atomic reference-counted smart pointer for shared ownership across threads.
  • Rc - A reference-counted smart pointer for single-threaded scenarios.
  • RefCell - Provides interior mutability with runtime borrowing checks for non-Copy types.
  • Box - A heap-allocated smart pointer.