不可变字符串和克隆



我的心态是保持我的String是不可变的,是真理的单一来源。当我对Rust抱着同样的心态时,我发现我必须做很多克隆。由于String不会更改,因此不需要进行所有克隆。下面是一个例子,并链接到相关的操场。

借款似乎不是一种选择,因为我必须处理参考资料和他们的一生。我的下一个想法是使用类似RcCow结构的东西。但是用Rc这样的东西包裹所有的String感觉不自然。在我对Rust的有限经验中,我从未见过任何公开的所有权/内存管理结构,即RcCow。我很好奇一个经验丰富的Rust开发人员会如何处理这样的问题。

在Rust中公开像RcCow这样的所有权/内存管理结构真的很自然吗?我应该用切片吗?

use std::collections::HashSet;
#[derive(Debug)]
enum Check {
Known(String),
Duplicate(String),
Missing(String),
Unknown(String)
}
fn main() {
let known_values: HashSet<_> = [
"a".to_string(),
"b".to_string(),
"c".to_string()]
.iter().cloned().collect();
let provided_values = vec![
"a".to_string(),
"b".to_string(),
"z".to_string(),
"b".to_string()
];
let mut found = HashSet::new();
let mut check_values: Vec<_> = provided_values.iter().cloned()
.map(|v| {
if known_values.contains(&v) {
if found.contains(&v) {
Check::Duplicate(v)
} else {
found.insert(v.clone());
Check::Known(v)
}
} else {
Check::Unknown(v)
}
}).collect();
let missing = known_values.difference(&found);
check_values = missing
.cloned()
.fold(check_values, |mut cv, m| {
cv.push(Check::Missing(m));
cv
});
println!("check_values: {:#?}", check_values);
}

从我的问题评论中的讨论来看,示例中所有不可变Strings的克隆都是正确的。克隆是必要的,因为Rust通过所有权而不是其他语言中的引用来处理内存。

充其量,在不使用Rc的情况下,我可以通过在provided_values上使用移动语义来减少克隆。

更新:一些有趣的阅读

  • https://www.reddit.com/r/rust/comments/5xjl95/rc_or_cloning/
  • https://medium.com/swlh/ownership-managing-memory-in-rust-ce7bf3f5c9d5
  • 如何创建具有字符串成员的Rust结构

Cow在我的示例中不起作用,因为它涉及引用的借用。Rc将是我必须使用的。在我的示例中,所有内容都必须转换为Rc,但我可以看到这一切都可能通过封装隐藏起来。


use std::collections::HashSet;
use std::rc::Rc;
#[derive(Debug)]
enum Check {
Known(Rc<String>),
Duplicate(Rc<String>),
Missing(Rc<String>),
Unknown(Rc<String>)
}
fn main() {
let known_values: HashSet<_> = [
Rc::new("a".to_string()),
Rc::new("b".to_string()),
Rc::new("c".to_string())]
.iter().cloned().collect();
let provided_values = vec![
Rc::new("a".to_string()),
Rc::new("b".to_string()),
Rc::new("z".to_string()),
Rc::new("b".to_string())
];
let mut found = HashSet::new();
let mut check_values: Vec<_> = provided_values.iter().cloned()
.map(|v| {
if known_values.contains(&v) {
if found.contains(&v) {
Check::Duplicate(v)
} else {
found.insert(v.clone());
Check::Known(v)
}
} else {
Check::Unknown(v)
}
}).collect();
let missing = known_values.difference(&found);
check_values = missing
.cloned()
.fold(check_values, |mut cv, m| {
cv.push(Check::Missing(m));
cv
});
println!("check_values: {:#?}", check_values);
}

游乐场

最新更新