如何将结构体属性更新为包含旧值的新值?
解决Rust中结构体属性更新为包含旧值的新值问题
你的代码核心问题是同时持有了结构体属性的不可变借用和可变借用:当你用match &self.container获取不可变引用时,又尝试对self.container赋值,这违反了Rust的借用规则(同一时间不能存在可变借用与不可变借用共存的情况)。
修正方案:使用Option::take转移所有权
利用Option的take方法,可以先将旧值从self.container中取出(同时将其置为None),这样就解除了借用限制,随后可以基于旧值创建新实例并赋值回去:
#[derive(Debug)] struct Container { more: Box<Container> } struct ContainerBox { container: Option<Container> } impl ContainerBox { pub fn ingest(&mut self, container: Container) { // 取出旧值,同时将self.container设为None if let Some(old_container) = self.container.take() { // 用旧值创建新的Container实例 self.container = Some(Container { more: Box::new(old_container), }); } else { // 原属性为空时,直接存入新值 self.container = Some(container); } } }
补充说明
- 为什么不用clone? 原代码中的
clone需要为Container实现Clonetrait,而且会额外复制数据。使用take直接转移所有权,既避免了借用冲突,又更高效。 - 如果你的业务逻辑确实需要保留旧值(而不是转移所有权),那才需要为
Container实现Clone,此时可以先克隆旧值再操作,比如:
#[derive(Debug, Clone)] struct Container { more: Box<Container> } impl ContainerBox { pub fn ingest(&mut self, container: Container) { if let Some(ref old_container) = self.container { // 克隆旧值创建新实例 self.container = Some(Container { more: Box::new(old_container.clone()), }); } else { self.container = Some(container); } } }
这种写法之所以可行,是因为我们在克隆完成后才进行赋值,此时不可变借用已经结束,不会和后续的可变赋值冲突。
内容的提问来源于stack exchange,提问作者Alesi Rowland
相关产品推荐
相关产品推荐

