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
,这样如果你需要的话,你可以改变它。