gpt4 book ai didi

rust - 类型能否知道对自身的可变借用何时结束?

转载 作者:行者123 更新时间:2023-11-29 07:58:04 25 4
gpt4 key购买 nike

我有一个结构,每次对它的可变借用结束时,我都想调用该结构的方法之一。为此,我需要知道对它的可变借用何时被删除。如何才能做到这一点?

最佳答案

免责声明:下面的答案描述了一种可能的解决方案,但它不是一个很好的解决方案,如 Sebastien Redl 的评论所述:

[T]his is a bad way of trying to maintain invariants. Mostly because dropping the reference can be suppressed with mem::forget. This is fine for RefCell, where if you don't drop the ref, you will simply eventually panic because you didn't release the dynamic borrow, but it is bad if violating the "fraction is in shortest form" invariant leads to weird results or subtle performance issues down the line, and it is catastrophic if you need to maintain the "thread doesn't outlive variables in the current scope" invariant.

不过,可以使用一个临时结构作为“暂存区”,在引用对象被删除时更新它,从而正确地保持不变量;然而,该版本基本上相当于制作了一个合适的包装器类型和一种奇怪的使用方式。解决此问题的最佳方法是通过不透明的包装器结构,该结构不会暴露其内部结构,除非通过明确保持不变性的方法。

废话不多说,原答案:


完全...但非常接近。我们可以使用 RefCell<T>作为如何做到这一点的模型。这是一个有点抽象的问题,但我会用一个具体的例子来证明。 (这不是一个完整的例子,而是展示一般原则的东西。)

假设您想制作一个 Fraction始终采用最简单形式的结构(完全简化,例如 3/5 而不是 6/10)。你写了一个结构 RawFraction将包含裸数据。 RawFraction实例总是最简单的形式,但它们有一个方法fn reduce(&mut self)这减少了它们。

现在您需要一个智能指针类型,您将始终使用它来改变 RawFraction ,它调用 .reduce()在指向的结构上,当它被删除时。我们称它为RefMut ,因为这是命名方案 RefCell使用。你实现 Deref<Target = RawFraction> , DerefMut , 和 Drop在上面,像这样:

pub struct RefMut<'a>(&'a mut RawFraction);

impl<'a> Deref for RefMut<'a> {
type Target = RawFraction;
fn deref(&self) -> &RawFraction {
self.0
}
}

impl<'a> DerefMut for RefMut<'a> {
fn deref_mut(&mut self) -> &mut RawFraction {
self.0
}
}

impl<'a> Drop for RefMut<'a> {
fn drop(&mut self) {
self.0.reduce();
}
}

现在,只要你有 RefMutRawFraction放下它,你知道 RawFraction之后将是最简单的形式。此时您需要做的就是确保 RefMut是获取 &mut唯一方法访问 RawFraction Fraction 的一部分.

pub struct Fraction(RawFraction);

impl Fraction {
pub fn new(numerator: i32, denominator: i32) -> Self {
// create a RawFraction, reduce it and wrap it up
}

pub fn borrow_mut(&mut self) -> RefMut {
RefMut(&mut self.0)
}
}

关注pub标记(以及缺少标记):我正在使用它们来确保暴露接口(interface)的完整性。这三种类型都应该单独放在一个模块中。标记 RawFraction 是不正确的领域 pub里面Fraction ,从那时起就可以(对于模块外的代码)创建一个未缩减的 Fraction不使用new或获取 &mut RawFraction无需通过RefMut .

假设所有这些代码都放在一个名为 frac 的模块中,你可以像这样使用它(假设 Fraction 实现了 Display ):

let f = frac::Fraction::new(3, 10);
println!("{}", f); // prints 3/10
f.borrow_mut().numerator += 3;
println!("{}", f); // prints 3/5

类型编码不变量:无论你在哪里Fraction ,你可以知道它已经完全减少了。当你有一个 RawFraction , &RawFraction等等,你不能确定。如果你愿意,你也可以制作RawFraction的字段非 pub , 所以你不能得到一个未减少的分数根本除非调用borrow_mutFraction 上.

关于rust - 类型能否知道对自身的可变借用何时结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47639897/

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