我如何基于Vec
中项目的信息来修改Vec
,而又不具有对向量的不变和可变引用?
我试图创建一个最小的示例来说明我的特定问题。在我的实际代码中,Builder
结构已经是其他答案提出的中间结构。具体而言,我认为其他问题不会回答这个问题,因为:
Vec<Item>
计算单独的值。正在[[is Vec<Item>
上修改/操作的值,并且是中间结构中需要的值Item
的嵌套列表,或指示应将一个新项目添加到正在处理的项目列表中:enum Item {
Direct(String),
Nested(Vec<Item>),
New(String),
}
还有一个构建器,它包含一个Vec<Item>
列表,并在指定的索引处构建一个项:
struct Builder { items: Vec<Item>, } impl Builder { pub fn build_item(&mut self, item: &Item, output: &mut String) { match item { Item::Direct(v) => output.push_str(v), Item::Nested(v) => { for sub_item in v.iter() { self.build_item(sub_item, output); } } Item::New(v) => self.items.push(Item::Direct(v.clone())), } } pub fn build(&mut self, idx: usize, output: &mut String) { let item = self.items.get(idx).unwrap(); self.build_item(item, output); } }
由于错误而无法编译:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable --> src/main.rs:26:9 | 25 | let item = self.items.get(idx).unwrap(); | ---------- immutable borrow occurs here 26 | self.build_item(item, output); | ^^^^^----------^^^^^^^^^^^^^^ | | | | | immutable borrow later used by call | mutable borrow occurs here error: aborting due to previous error For more information about this error, try `rustc --explain E0502`.
我不知道如何基于其中一项的信息(即[的不可变借项]来修改Builder
结构(即对items
进行可变引用)) C0])。这里是代码的
self.items
。使用
self.items
@@ Stargateur建议我尝试克隆playground example中的项目。尽管这确实可行,但由于性能原因,我一直尝试不克隆项目。
UPDATE:我没有在
有效的代码(Clone
中添加build()
修改功能,而是在我的真实代码中实现了Vec<Item>
方法,并克隆了与上述示例Item::New
方法等效的值。当我执行clone()
与build()
时,性能下降了12倍。我将继续寻找其他解决方案。问题是,我对Rust还是比较陌生,甚至不确定使用不安全的代码也不确定如何修改规则/做其他事情。self.items.get(idx).unwrap().clone()
)
self.items.get(idx).unwrap()
并更改playground首先克隆该项目:
impl Clone for Item { fn clone(&self) -> Self { match self { Item::Direct(v) => Item::Direct(v.clone()), Item::Nested(v) => Item::Nested(v.clone()), Item::New(v) => Item::New(v.clone()), } } }
build
中的 let item = self.items.get(idx).unwrap().clone();
vec借用(即,您不能将项目移出items
或复制/克隆它),并且您必须将此项目的引用传递给build
,则可能想考虑将您的self.items
函数重写为not变异build_item
。在这种情况下,build_item
只会在self
的末尾附加新项目,这使我们可以进行有趣的重构:而不是让build_item
修改self.items
,而是使其返回要添加到原始项目的项目。向量,然后让caller将新生成的项添加到build_item
向量。
items
注意,为了保留API,已将items
函数重命名为impl Builder { fn generate_items(&self, item: &Item, output: &mut String) -> Vec<Item> { match item { Item::Direct(v) => { output.push_str(v); Vec::new() } Item::Nested(v) => { v.iter() .flat_map(|sub_item| self.generate_items(sub_item, output)) .collect() } Item::New(v) => vec![Item::Direct(v.clone())], } } pub fn build_item(&mut self, item: &Item, output: &mut String) { let mut new_items = self.generate_items(item, output); self.items.append(&mut new_items); } pub fn build(&mut self, idx: usize, output: &mut String) { // Non lexical lifetimes allow this to compile, as the compiler // realizes that `item` borrow can be dropped before the mutable borrow // Immutable borrow of self starts here let item = self.items.get(idx).unwrap(); let mut new_items = self.generate_items(item, output); // Immutable borrow of self ends here // Mutable borrow of self starts here self.items.append(&mut new_items); } }
,并创建了一个使用build_item
的新generate_items
函数。[如果仔细看,您会发现
build_item
甚至不需要generate_items
,并且可以是generate_items
中的独立函数或静态函数。
self