Cow

Cow 是一種非常方便的列舉。它的意思是"寫時克隆",如果你不需要 String,可以回傳 &str,如果你需要就回傳 String。(它也可以對陣列與向量等等做同樣的處理)。

為了理解它,我們看一下簽名。它說:

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

fn main() {}

你馬上就知道,'a 意味著它可以和參考一起用。ToOwned 特徵意味著它是個可以轉換成具有擁有權的型別。例如,str 通常是參考(&str),你可以把它轉換成具有擁有權的 String

接下來是 ?Sized。這意味著"也許是 Sized,但也許不是"。Rust 中幾乎每個型別都是 Sized 的,但像 str 這樣的型別卻不是。這就是為什麼我們需要附帶 &str,因為編譯器不知道大小。所以如果你想要可以用像是 str 的特徵,你可以加上 ?Sized

接下來是 enum 的變體。它們是 BorrowedOwned

想像你有個回傳 Cow<'static, str> 的函式。如果你告訴函式回傳 "My message".into(),它就會檢視型別:"My message"是 str。這是個 Borrowed 型別,所以它選擇 Borrowed(&'a B)。那它就變成了 Cow::Borrowed(&'static str)

而如果你給它 format!("{}", "My message").into(),那麼它就會檢視型別。這次是個 String,因為 format! 做出 String。那這次就會選擇 "Owned"。

這是個測試 Cow 的範例。我們將把數字放入會回傳 Cow<'static, str> 的函式中。根據這個數字,它會建立 &strString。然後用 .into() 將其變成 Cow。這樣做的時候,它就會選擇 Cow::Borrowed 或者 Cow::Owned 其中之一。那我們就匹配看看它選的是哪一個。

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

印出:

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 還有一些其他方法,像是 into_owned 或者 into_borrowed,如果你需要就可以改變它。