我有一个大型结构体,其中包含
String
向量作为成员。我正在尝试迭代这些并将每个传递给另一个采用 &str
参数的方法。后一种方法需要 &mut self
才能处理输入流,而我似乎无法协调借用。
我将其归结为一个简单的(?)示例来显示我遇到的问题。请参阅下文,以及指向 Rust 游乐场上的代码
的链接
pub struct Configuration {
pub prefixes: Vec<String>,
}
impl Configuration {
pub fn check_one(&mut self, prefix: &str) -> bool {
"testy".starts_with(prefix)
}
pub fn check(&mut self) -> bool {
for prefix in &self.prefixes {
if self.check_one(prefix) {
return true;
}
}
return false;
}
}
fn main() {
let mut config = Configuration{ prefixes: vec!["fl".to_string()], };
dbg!(config.check());
}
实际问题。如果我将参数作为引用 (
self.check_one(&prefix)
),那么我会遇到一个问题,即 self.prefixes
被 into_iter()
移动,并且编译器建议使用 &self.prefixes
。美好的。但如果我尝试that,我会被告知,当我已经可变地借用它时,我不能一成不变地借用self
,而且我似乎无法调和这两者。
底线是我需要将成员向量中的每个
String
传递给方法进行检查。我不想修改字符串或向量,但我必须借用 &self
作为可变的。有建议吗?
当借用
&mut self
的一部分时,无法调用采用 self
的方法。这是因为采用 &mut self
的方法可以修改 self
的任何部分。您无法创建仅允许修改 self
的一部分的 方法。
如所写,
check_one
应采用 &self
。在 check
内部,调用 &mut self
时,&self
会自动转换为 check_one
。
pub fn check_one(&self, prefix: &str) -> bool {
"testy".starts_with(prefix)
}
如果您需要能够修改
self
的所有部分,包括 prefixes
,那么您需要克隆 prefixes
,以便 self
拥有的副本不会被借用。
for prefix in &self.prefixes.clone() {
if self.check_one(prefix) {
return true;
}
}
如果您不需要对
prefixes
进行可变或不可变访问,那么您可以执行以下两件事之一。首先,您可以创建一个常规函数来获取 self
的其他部分。
// Replace `()` with the other parts of `self`
pub fn check_one(_other_parts: (), prefix: &str) -> bool {
"testy".starts_with(prefix)
}
for prefix in &self.prefixes {
if check_one((), prefix) {
return true;
}
}
或者您可以暂时从 prefixes
拿
self
,完成后放回去。
pub fn check(&mut self) -> bool {
let prefixes = std::mem::take(&mut self.prefixes);
for prefix in &prefixes {
if self.check_one(prefix) {
self.prefixes = prefixes;
return true;
}
}
self.prefixes = prefixes;
return false;
}
最后,一种不太常见的情况是
check_one
可能会也可能不会修改 prefixes
,具体取决于数据。在这种情况下,为了仅在必要时克隆 prefixes
,您可以使用 Rc
或 Arc
。这是一个更广泛的变化。
pub struct Configuration {
pub prefixes: Rc<Vec<String>>,
}
impl Configuration {
pub fn check_one(&mut self, prefix: &str) -> bool {
let check = "testy".starts_with(prefix);
// Do some mutable work
if check {
Rc::make_mut(&mut self.prefixes).push("new".to_string());
}
return check;
}
pub fn check(&mut self) -> bool {
// The only change needed here is a dereference
for prefix in &*self.prefixes.clone() {
if self.check_one(prefix) {
return true;
}
}
return false;
}
}
当您克隆
Rc
本身时,它会创建第二个指向相同数据的只读引用。当存在多个引用时,调用 make_mut
将克隆数据,从而为您提供对数据的可变访问。在这种情况下,第一次调用 make_mut
时,数据将被克隆,Rc
将用包含克隆数据的新 Rc
替换自身,并返回一个可变引用。如果在同一个循环中再次调用 make_mut
,它只会返回一个可变引用,因为它不再链接到另一个 Rc
。