Cow

Cow adalah enum yang cukup membantu. Ia singkatan dari "clone on write" dan memungkinkan Anda mengembalikan &str jika Anda tidak membutuhkan String, dan mengembalikan String jika Anda memerlukannya. (Ia juga bisa melakukan hal yang sama pada array vs. Vecs, dan lainnya.)

Untuk memahami ini, mari kita lihat signaturenya. Seperti ini:

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

fn main() {}

Anda langsung mengetahui bahwa 'a artinya ia bekerja dengan reference. Trait ToOwned artinya bahwa ia adalah type yang bisa diubah menjadi sebuah owned type. Contohnya, str biasanya adalah reference (&str) dan Anda bisa mengubahnya menjadi owned type seperti String.

Selanjutnya adalah ?Sized. Ini berari "mungkin Sized, mungkin juga bukan". Hampis semua type di dalam Rust adalah Sized, namun type seperti str adalah bukan. Itulah mengapa kita memerlukan & untuk str, karen compiler tidak mengetahui sizenya. Sehingga, jika Anda menginginkan sebuah trait yang bisa menggunakan sesuatu seperti str, Anda tambahkan ?Sized.

Selanjutnya adalah variant enumnya. Yaitu Borrowed dan Owned.

Bayangkan, Anda memiliki function yang mengembalikan Cow<'static, str>. Jika Anda memberitahu function untuk mengembalikan "My message".into(), ia akan memeriksa pada typenya: "My message" adalah str. Ini merupakan type Borrowed, jadi ia memilih Borrowed(&'a B). Sehingga ia menjadi Cow::Borrowed(&'static str).

Dan jika Anda memberikan format!("{}", "My message").into(), ia pun akan memeriksa typenya. Dan ini merupakan String, karena format! membuat sebuah String. Sehingga untuk kali ini ia akan memilih "Owned".

Ini adalah contoh untuk melakukan test pada Cow. Kita akan meletakkan sebuah angka ke dalam function yang mengembalikan Cow<'static, str>. Kita akan membuat sebuah &str atau String, tergantung dari angkanya. Kemudian ia menggunakan .into() untuk mengubahnya menjadi Cow. Di saat Anda melakukan hal tersebut, ia akan memilih antara Cow::Borrowed atau Cow::Owned. Kemudian kita gunakan match untuk melihat yang mana yang akan dipilih oleh Cow.

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),
        }
    }
}

Hasilnya adalah:

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 memiliki method yang lain seperti into_owned atau into_borrowed sehingga Anda bisa menggantinya jika Anda merasa perlu melakukannya.