- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个结构,每次对它的可变借用结束时,我都想调用该结构的方法之一。为此,我需要知道对它的可变借用何时被删除。如何才能做到这一点?
最佳答案
免责声明:下面的答案描述了一种可能的解决方案,但它不是一个很好的解决方案,如 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 forRefCell
, 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();
}
}
现在,只要你有 RefMut
到 RawFraction
放下它,你知道 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_mut
在 Fraction
上.
关于rust - 类型能否知道对自身的可变借用何时结束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47639897/
编辑备注 由于 Rust(版本:1.42)仍然没有稳定的 ABI ,推荐使用extern (目前相当于extern "C"(将来可能会改变))否则,可能需要重新编译库。 This article解释如
词法分析器/解析器文件位于 here非常大,我不确定它是否适合只检索 Rust 函数列表。也许我自己编写/使用另一个库是更好的选择? 最终目标是创建一种执行管理器。为了上下文化,它将能够读取包装在函数
我试图在 Rust 中展平 Enum 的向量,但我遇到了一些问题: enum Foo { A(i32), B(i32, i32), } fn main() { let vf =
我正在 64 位模式下运行的 Raspberry Pi 3 上使用 Rust 进行裸机编程。我已经实现了一个自旋锁,如下所示: use core::{sync::atomic::{AtomicBool
我无法理解以下示例是如何从 this code 中提炼出来的, 编译: trait A: B {} trait B {} impl B for T where T: A {} struct Foo;
在我写了一些代码和阅读了一些文章之后,我对 Rust 中的移动语义有点困惑,我认为值移动后,它应该被释放,内存应该是无效的。所以我尝试写一些代码来作证。 第一个例子 #[derive(Debug)]
https://doc.rust-lang.org/reference/types/closure.html#capture-modes struct SetVec { set: HashSe
考虑 const-generic 数据结构的经典示例:方矩阵。 struct Matrix { inner: [[T; N]; N] } 我想返回一个结构体,其 const 参数是动态定义的:
以下代码无法编译,因为 x在移动之后使用(因为 x 具有类型 &mut u8 ,它没有实现 Copy 特性) fn main() { let mut a: u8 = 1; let x:
我在玩 Rust,发现了下面的例子: fn main() { let mut x = [3, 4, 5].to_vec(); x; println!("{:?}", x); }
假设一个 Rust 2018 宏定义了一个 async里面的功能。它将使用的语法与 Rust 2015 不兼容。因此,如果您使用 2015 版编译您的 crate,那么宏中的扩展代码不会与它冲突吗?
假设我有一些 Foo 的自定义集合s: struct Bar {} struct Foo { bar: Bar } struct SubList { contents: Vec, }
代码如下: fn inner(x:&'a i32, _y:&'b i32) -> &'b i32 { x } fn main() { let a = 1; { let b
在lifetime_things的定义中,'b的生命周期比'a长,但实际上当我调用这个函数时,x1比y1长,但是这样可以编译成功: //here you could see 'b:'a means
我正在尝试检索 FLTK-RS Widget 周围的 Arc Mutex 包装器的内部值: pub struct ArcWidget(Arc>); impl ArcWidget{ pub
如下代码所示,我想封装一个定时函数,返回一个闭包的结果和执行时间。 use tap::prelude::Pipe; use std::time::{Instant, Duration}; pub fn
我想实现自己的通用容器,这是我正在使用的特征的片段: pub trait MyVec where Self: Default + Clone + IntoIterator, Self:
所需代码: 注释掉的块可以编译并工作,但是我想从嵌套的匹配样式转变为更简洁的函数链 async fn ws_req_resp(msg: String, conn: PgConn) -> Result>
我正在尝试编写一些代码,该代码将生成具有随机值的随机结构。对于结构,我具有以下特征和帮助程序宏: use rand::{thread_rng, Rng}; use std::fmt; pub trai
我有一个带有函数成员的结构: struct Foo { fun: Box, } type FooI = Foo; 这不起作用: error[E0106]: missing lifetime s
我是一名优秀的程序员,十分优秀!