Reference 每当删除对源数据的可变引用时,如何重新缓存数据?

Reference 每当删除对源数据的可变引用时,如何重新缓存数据?,reference,rust,mutable,Reference,Rust,Mutable,我有一个名为Spire的结构,其中包含一些数据(元素),以及一个可以从这些数据计算出的一些结果的缓存。当元素更改时,我希望能够自动更新缓存(例如,在这种情况下,结构的用户不必手动调用更新高度) 我想知道我如何才能做到这一点,或者是否有更好的方法来做我想做的事情 struct Spire{ 元素:Vec, 高度:i32, } 植入尖顶{ 酒吧fn新(元素:Vec)->塔尖{ 放出塔尖{ 元素:元素, 高度:0,, }; out.update_height(); 出来 } 发布fn获取元素mut(&

我有一个名为
Spire
的结构,其中包含一些数据(
元素
),以及一个可以从这些数据计算出的一些结果的缓存。当
元素
更改时,我希望能够自动更新缓存(例如,在这种情况下,结构的用户不必手动调用
更新高度

我想知道我如何才能做到这一点,或者是否有更好的方法来做我想做的事情

struct Spire{
元素:Vec,
高度:i32,
}
植入尖顶{
酒吧fn新(元素:Vec)->塔尖{
放出塔尖{
元素:元素,
高度:0,,
};
out.update_height();
出来
}
发布fn获取元素mut(&mut self)->&mut Vec{
&多自元
}
发布fn更新高度(多个自){
self.height=self.elements.iter().sum();
}
发布fn高度(和自身)->i32{
自我高度
}
}
fn main(){
让mut spire=spire::new(vec![1,2,3,1]);
//获取对内部元素的可变引用
让spire_elems=spire.get_elems_mut();
//用元素做一些事情
spire_elems.pop();
尖顶推力(7);
顶推式(10);
//编译器不允许您获取高度
//不首先删除可变引用
//dbg!(尖顶高度());
//完成后,删除对图元的引用。
下降(尖顶);
//我想在这里自动运行update_height()
dbg!(尖顶高度());
}


我正在尝试为可变引用找到类似于
Drop
特性的行为。

至少有两种方法可以解决这个问题。不要直接调用
drop
,而应将执行变异的代码放入新范围,以便将作用域规则自动应用于它们,并为您自动调用
drop

fn main(){
让mut spire=spire::new(vec![1,2,3,1]);
{
让spire_elems=spire.get_elems_mut();
spire_elems.pop();
尖顶推力(7);
顶推式(10);
}
塔尖。更新_高度();
dbg!(尖顶高度());
}
如果您编译这个,它将按预期工作。一般来说,如果您必须手动调用
drop
,通常意味着您正在做一些不应该做的事情

话虽如此,更有趣的问题是设计一个不会泄露抽象的API。例如,您可以通过提供操作内部数据结构表示的方法来保护内部数据结构表示(这有几个优点,其中之一是您可以在以后自由更改您在内部使用的数据结构,而不会影响代码的其他部分),例如

impl尖顶{
pub fn push(和mut self,元素:i32){
自我元素推送(elem);
self.update_internals();
}
}
本例调用一个名为
update\u internals
的私有方法,该方法在每次更新后负责内部数据的一致性

如果您只想在所有添加和删除发生时更新内部值,那么您应该实现一个最终确定方法,每次修改完
Spire
实例时都必须调用该方法,例如

spire.pop();
顶推(7);
顶推(10);
spire.commit();
要实现这一点,您至少还有两个选择:您可以像上面的示例那样执行,或者您可以使用构建器模式,在一系列调用中进行修改,然后只有在调用链上的最后一个最终调用时才会生效。比如:

spire.remove_last().add(7).add(10).finalize();
另一种方法是使用一个内部标志(一个简单的
bool
就可以了),每次插入或删除时,该标志都会更改为
true
。您的
height
方法可以在内部缓存计算出的数据(例如,使用一些
单元格
类型进行内部可变),如果标志为
true
,则它将重新计算值并将标志设置回
false
。在您进行另一次修改之前,它将在每次后续调用中返回缓存的值。下面是一个可能的实现:

使用std::cell::cell;
结构尖顶{
元素:Vec,
高度:单元格,
更新:Cell,
}
植入尖顶{
fn计算高度(要素:&[i32])->i32{
elements.iter().sum()
}
pub fn new(元素:Vec)->Self{
自我{
高度:单元格::新建(自身::计算高度(&元素)),
元素,
更新:单元格::新建(错误),
}
}
pub fn push(和mut self,元素:i32){
self.updated.set(true);
自我元素推送(elem);
}
pub fn pop(&mut self)->选项{
self.updated.set(true);
self.elements.pop()
}
发布fn高度(和自身)->i32{
如果self.updated.get(){
self.height.set(self::calc_height(&self.elements));
self.updated.set(false);
}
self.height.get()
}
}
fn main(){
让mut spire=spire::new(vec![1,2,3,1]);
spire.pop();
顶推(7);
顶推(10);
dbg!(尖顶高度());
}
如果您不介意在
height
getter中可变地借用
self
,那么就不用麻烦
单元格
,直接更新值即可。

第三个选项,