Cow
Cow是一个非常方便的枚举。它的意思是 "写时克隆",如果你不需要String,可以返回一个&str,如果你需要,可以返回一个String。(它也可以对数组与Vec等做同样的处理)。
为了理解它,我们看一下签名。它说
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 这样的trait,你可以添加 ?Sized.
接下来是enum的变种。它们是 Borrowed 和 Owned。
想象一下,你有一个返回 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>。根据这个数字,它会创建一个&str或String。然后它使用.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,这样如果你需要的话,你可以改变它。