Cow
Cow说明
Cow 适合“多数情况下借用,少数情况下修改”的场景
Cow 的核心价值是:尽量不分配,只有必要时才分配
- 能借用就借用,需要修改时才拷贝成拥有的数据。
基本类型
use std::borrow::Cow;
Cow<'a, str>
两种状态
// 不分配内存,返回借用
Cow::Borrowed(&'a str)
// 在需要时才创建
Cow::Owned(String)
问题说明
有时直接返回借用的字符串,不分配内存
有时需要生成新的字符串
// 这里即使只是返回原始 name,也必须 .to_string(),会发生分配。
// 用 Cow 可以避免不必要的分配
fn check_user_name(name: &str) -> String {
if name == "admin" {
let s = format!("{}-{}", name, "hello");
s
} else {
name.to_string()
}
}
fn main() {
let res = check_user_name("demo");
println!("res: {}", res);
}
解决方法
Cow<'_, str>中'_让编译器自动推断这个生命周期- 等价于
fn check_user_name<'a>(name: &'a str) -> Cow<'a, str>
- 等价于
use std::borrow::Cow;
fn check_user_name(name: &str) -> Cow<'_, str> {
if name == "admin" {
Cow::Owned(format!("{}-{}", name, "hello"))
} else {
Cow::Borrowed(name)
}
}
fn main() {
let res: Cow<'_, str> = check_user_name("demo");
println!("res: {}", res);
}
res: demo
解释说明
Cow<'a, str> 里 'a 是什么
'a 是生命周期。
它表示:这个 Cow 里如果是借用数据,那么它借用的那份数据至少要活到 'a 这么久。
// 输入的 name 活多久
// 返回的 Cow 里如果借用了它,也只能活这么久
fn f<'a>(name: &'a str) -> Cow<'a, str>
为什么不是Cow<'a, &str>
因为
&str本身已经是一个引用类型了
Cow<'a, &str>Borrowed会是&&strOwned也会对应&str的owned类型,但这不符合 Cow 的常规用途
// B 是底层类型
// Borrowed 里才会再加一层 &
enum Cow<'a, B>
where
B: ToOwned + ?Sized,
{
Borrowed(&'a B),
Owned(<B as ToOwned>::Owned),
}
为什么不是Cow<'a, String>
因为 Cow 不是“借用 String 或拥有 String”这么简单。
它是: 借用某种数据 B,或者拥有它对应的 Owned 类型。
- 对于 str:
- 借用时是 &str
- 拥有时是 String
// Borrowed 存的是 &'a B
// Owned 存的是 B::Owned
Cow<'a, B>
Cow类型
Cow 可以用于很多类型,只要这个类型实现了
ToOwned
&str/String
Cow<'a, str>
= Borrowed(&'a str)
= Owned(String)
数组/切片:
Cow<'a, [u8]>
= Borrowed(&'a [u8])
= Owned(Vec<u8>)
Path/PathBuf
Cow<'a, std::path::Path>
= Borrowed(&'a std::path::Path)
= Owned(std::path::PathBuf)
OsStr/OsString
Cow<'a, std::ffi::OsStr>
= Borrowed(&'a std::ffi::OsStr)
= Owned(std::ffi::OsString)
Cow常用方法
to_mut()
to_mut()会在当前是Borrowed时自动克隆成Owned,然后返回可变引用
use std::borrow::Cow;
fn check_user_name(name: &str) -> Cow<'_, str> {
if name == "admin" {
Cow::Owned(format!("{}-{}", name, "hello"))
} else {
Cow::Borrowed(name)
}
}
fn main() {
let mut res: Cow<'_, str> = check_user_name("demo");
let res1: &mut String = res.to_mut();
res1.push('a');
println!("res1: {}", res1);
}
res1: demoa
into_owned()
into_owned()会把Cow转成真正拥有的数据,Borrowed会clone,Owned直接拿走。
use std::borrow::Cow;
fn check_user_name(name: &str) -> Cow<'_, str> {
if name == "admin" {
Cow::Owned(format!("{}-{}", name, "hello"))
} else {
Cow::Borrowed(name)
}
}
fn main() {
let res: Cow<'_, str> = check_user_name("demo");
let mut res1: String = res.into_owned();
res1.push('b');
println!("res: {}", res1);
}
res1: demob
as_ref()
如果只是想拿引用,不关心 owned / borrowed
use std::borrow::Cow;
fn check_user_name(name: &str) -> Cow<'_, str> {
if name == "admin" {
Cow::Owned(format!("{}-{}", name, "hello"))
} else {
Cow::Borrowed(name)
}
}
fn main() {
let res: Cow<'_, str> = check_user_name("demo");
let res1: &str = res.as_ref();
println!("res1: {}", res1);
}
res1: demo

浙公网安备 33010602011771号