gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 08:15:29 24 4
gpt4 key购买 nike

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

我正在努力弄清楚如何才能实现这一点,或者是否有更好的方法来完成我想做的事情。

struct Spire {
elements: Vec<i32>,
height: i32,
}

impl Spire {
pub fn new(elements: Vec<i32>) -> Spire {
let mut out = Spire {
elements: elements,
height: 0,
};
out.update_height();
out
}

pub fn get_elems_mut(&mut self) -> &mut Vec<i32> {
&mut self.elements
}

pub fn update_height(&mut self) {
self.height = self.elements.iter().sum();
}

pub fn height(&self) -> i32 {
self.height
}
}

fn main() {
let mut spire = Spire::new(vec![1, 2, 3, 1]);

// Get a mutable reference to the internal elements
let spire_elems = spire.get_elems_mut();

// Do some stuff with the elements
spire_elems.pop();
spire_elems.push(7);
spire_elems.push(10);

// The compiler won't allow you to get height
// without dropping the mutable reference first
// dbg!(spire.height());

// When finished, drop the reference to the elements.
drop(spire_elems);
// I want to automatically run update_height() here somehow

dbg!(spire.height());
}

Playground

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

最佳答案

至少有两种方法可以解决这个问题。不要直接调用 drop,您应该将执行突变的代码放在一个新的范围内,这样范围规则将自动应用于它们并且 drop 将被自动调用给你:

fn main() {
let mut spire = Spire::new(vec![1, 2, 3, 1]);

{
let spire_elems = spire.get_elems_mut();
spire_elems.pop();
spire_elems.push(7);
spire_elems.push(10);
}

spire.update_height();
dbg!(spire.height());
}

如果你编译它,它将按预期工作。一般来说,如果您必须手动调用 drop,这通常意味着您正在做一些您不应该做的事情。

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

impl Spire {
pub fn push(&mut self, elem: i32) {
self.elements.push(elem);
self.update_internals();
}
}

此示例调用一个名为 update_internals 的私有(private)方法,该方法负责在每次更新后确保内部数据的一致性。

如果您只想在所有添加和删除操作完成后更新内部值,那么您应该实现一个finalising 方法,您必须在每次完成修改您的Spire 时调用该方法 实例,例如

spire.pop();
spire.push(7);
spire.push(10);
spire.commit();

要实现这样的目标,您至少有另外两个选择:您可以像上面的示例那样做,或者您可以使用构建器模式,在该模式中您在一系列调用中进行修改,只有当您调用链上的最后一个终结调用。像这样的东西:

spire.remove_last().add(7).add(10).finalise();

另一种方法可能是有一个内部标志(一个简单的 bool 就可以),每次插入或删除时都会更改为 true。您的 height 方法可以在内部缓存计算数据(例如,使用一些 Cell 类型来实现内部可变性),如果标志为 true 则它将重新计算值并将标志设置回 false。它将在每次后续调用中返回缓存的值,直到您进行另一次修改。这是一个可能的实现:

use std::cell::Cell;

struct Spire {
elements: Vec<i32>,
height: Cell<i32>,
updated: Cell<bool>,
}

impl Spire {
fn calc_height(elements: &[i32]) -> i32 {
elements.iter().sum()
}

pub fn new(elements: Vec<i32>) -> Self {
Self {
height: Cell::new(Self::calc_height(&elements)),
elements,
updated: Cell::new(false),
}
}

pub fn push(&mut self, elem: i32) {
self.updated.set(true);
self.elements.push(elem);
}

pub fn pop(&mut self) -> Option<i32> {
self.updated.set(true);
self.elements.pop()
}

pub fn height(&self) -> i32 {
if self.updated.get() {
self.height.set(Self::calc_height(&self.elements));
self.updated.set(false);
}
self.height.get()
}
}

fn main() {
let mut spire = Spire::new(vec![1, 2, 3, 1]);
spire.pop();
spire.push(7);
spire.push(10);
dbg!(spire.height());
}

如果您不介意在 height getter 中可变地借用 self,那么就不必理会 Cell,只需更新直接值。

关于reference - 每当删除对源数据的可变引用时,如何重新缓存数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56391687/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com