如何迭代结构体中的字符串向量且不移动?解决Rust借用冲突
Rust结构体可变借用与不可变借用冲突的解决方法
你遇到的是Rust借用规则的典型冲突:在check方法中,你先通过&self.prefixes获取了结构体成员的不可变借用,随后调用self.check_one(prefix)又需要获取整个结构体的可变借用。根据Rust的借用规则,同一时间内不能同时存在一个可变借用和任意数量的不可变借用,哪怕它们访问的是结构体的不同字段。
以下是几种针对性的解决方法:
方案一:提前收集引用到临时变量
先把prefixes的所有引用收集到一个临时变量中,释放对self.prefixes的不可变借用后,再进行可变借用调用check_one。这种方法最简单,几乎没有性能开销(仅复制字符串引用):
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 { // 提前收集所有prefix的引用,释放对self.prefixes的不可变借用 let prefix_refs: Vec<&str> = self.prefixes.iter().map(|s| s.as_str()).collect(); for prefix in prefix_refs { if self.check_one(prefix) { return true; } } false } } fn main() { let mut config = Configuration{ prefixes: vec!["fl".to_string()], }; dbg!(config.check()); }
方案二:拆分结构体字段(推荐)
如果check_one方法只需要修改结构体中与prefixes无关的字段,建议将结构体拆分为两个部分:存放只读数据的部分和需要修改的状态部分。这样可以从根源避免借用冲突,更符合Rust的所有权设计哲学:
// 拆分出需要修改的状态 #[derive(Default)] pub struct CheckState { // 这里存放check_one需要修改的字段,比如输入流状态等 } pub struct Configuration { pub prefixes: Vec<String>, pub state: CheckState, } impl Configuration { // 改为接受状态的可变引用,而非整个结构体的可变引用 pub fn check_one(state: &mut CheckState, prefix: &str) -> bool { // 在这里修改state的字段 "testy".starts_with(prefix) } pub fn check(&mut self) -> bool { // 只借用prefixes的不可变引用,同时借用state的可变引用,两者无冲突 for prefix in &self.prefixes { if Self::check_one(&mut self.state, prefix) { return true; } } false } } fn main() { let mut config = Configuration{ prefixes: vec!["fl".to_string()], state: CheckState::default(), }; dbg!(config.check()); }
方案三:使用内部可变性(兜底方案)
如果上述两种方法都不适用,可以使用RefCell实现内部可变性,将prefixes包装在RefCell中,这样可以在持有结构体可变引用的同时,获取prefixes的不可变引用。注意这种方法会带来运行时检查开销,且可能因借用冲突触发panic,仅在必要时使用:
use std::cell::RefCell; pub struct Configuration { pub prefixes: RefCell<Vec<String>>, } impl Configuration { pub fn check_one(&mut self, prefix: &str) -> bool { "testy".starts_with(prefix) } pub fn check(&mut self) -> bool { // 通过RefCell获取不可变引用 let prefixes = self.prefixes.borrow(); for prefix in &*prefixes { if self.check_one(prefix) { return true; } } false } } fn main() { let mut config = Configuration{ prefixes: RefCell::new(vec!["fl".to_string()]), }; dbg!(config.check()); }
内容的提问来源于stack exchange,提问作者tetricyclone
相关产品推荐
相关产品推荐

