Cow

Cow is a very convenient enum. It means "clone on write" and lets you return a &str if you don't need a String, and a String if you need it. (It can also do the same with arrays vs. Vecs, etc.)

To understand it, let's look at the signature. It says:

pub enum Cow<'a, B>
where
    B: 'a + ToOwned + ?Sized,
 {
    Borrowed(&'a B),
    Owned(<B as ToOwned>::Owned),
}

fn main() {}

You know right away that 'a means it works with references. The ToOwned trait means that it is a type that can be turned into an owned type. For example, str is usually a reference (&str) and you can turn it into an owned String.

Next is ?Sized. This means "maybe Sized, but maybe not". Almost every type in Rust is Sized, but types like str are not. That is why we need a & for a str, because the compiler doesn't know the size. So if you want a trait that can use something like a str, you add ?Sized.

Next are the enum variants. They are Borrowed and Owned.

Imagine that you have a function that returns Cow<'static, str>. If you tell the function to return "My message".into(), it will look at the type: "My message" is a str. This is a Borrowed type, so it chooses Borrowed(&'a B). So it becomes Cow::Borrowed(&'static str).

And if you give it a format!("{}", "My message").into() then it will look at the type. This time it is a String, because format! makes a String. So this time it will select "Owned".

Here is an example to test Cow. We will put a number into a function that returns a Cow<'static, str>. Depending on the number, it will create a &str or a String. Then it uses .into() to turn it into a Cow. When you do that, it will choose either Cow::Borrowed or Cow::Owned. Then we will match to see which one it chose.

use std::borrow::Cow;

fn modulo_3(input: u8) -> Cow<'static, str> {
    match input % 3 {
        0 => "Remainder is 0".into(),
        1 => "Remainder is 1".into(),
        remainder => format!("Remainder is {}", remainder).into(),
    }
}

fn main() {
    for number in 1..=6 {
        match modulo_3(number) {
            Cow::Borrowed(message) => println!("{} went in. The Cow is borrowed with this message: {}", number, message),
            Cow::Owned(message) => println!("{} went in. The Cow is owned with this message: {}", number, message),
        }
    }
}

This prints:

1 went in. The Cow is borrowed with this message: Remainder is 1
2 went in. The Cow is owned with this message: Remainder is 2
3 went in. The Cow is borrowed with this message: Remainder is 0
4 went in. The Cow is borrowed with this message: Remainder is 1
5 went in. The Cow is owned with this message: Remainder is 2
6 went in. The Cow is borrowed with this message: Remainder is 0

Cow has some other methods like into_owned or into_borrowed so you can change it if you need to.