【发布时间】:2021-09-28 10:45:37
【问题描述】:
我有以下代码:
use scopeguard::{guard, ScopeGuard}; // 1.1.0
struct S; // comes from a crate, non-clonable
impl S {
fn free(&mut self, _: u32) {}
}
fn bar(_: &mut S) -> Result<(), ()> {
Err(())
}
fn test(s: &mut S) -> Result<u32, ()> {
let i = 10u32; // assuming this is an object from some crate, not just normal u32
let sg = guard(i, |i| {
s.free(i); // guarding the object. If something goes wrong the object should be freed.
});
let _ = bar(s)?; // assuming this can fail and the previously created object `i` should be freed before the function returns
// here goes a lot of similar procedures:
// - first, create an object
// - second, wrap it in a guard closure
// now if any of the procedures fail, all previously created objects will be freed
Ok(ScopeGuard::into_inner(sg))
}
fn main() {
let mut s = S {};
let _ = test(&mut s);
}
编译错误消息失败:
error[E0501]: cannot borrow `*s` as mutable because previous closure requires unique access
--> src/lib.rs:20:17
|
16 | let sg = guard(i, |i| {
| --- closure construction occurs here
17 | s.free(i); // guarding the object. Is something goes wrong the object should be freed.
| - first borrow occurs due to use of `*s` in closure
...
20 | let _ = bar(s)?; // assuming this can fail and the previoously created object `i` should be freed before the function returns
| ^ second borrow occurs here
21 |
22 | Ok(ScopeGuard::into_inner(sg))
| -- first borrow later used here
我需要创建很多对象,其中每个对象都依赖于另一个对象或其他一些输入参数。我使用了scopeguard crate,但这在这里并不重要——最后,创建了一个闭包,它捕获了它的环境并且不允许我使用捕获的对象。
据我了解,s 对象是一个可变引用,第一个借用与第二个借用重叠,这在 Rust 中是不允许的。我正在寻找解决方法或完全不同的惯用方式来解决我的任务。
【问题讨论】:
-
@UlrichEckhardt 我知道如何使用搜索。您的链接没有回答如何以惯用方式解决我的特定任务的问题。
-
范围保护需要对不相关变量
s进行可变访问似乎有点错误。什么是s,为什么作用域守卫需要改变它? -
@SvenMarnach 在我的例子中
s是vulkan::Allocator。分配器需要分配/释放 vulkan 内存,这就是它是可变引用的原因。 scopeguard 采用FnOnce类型的闭包,该闭包捕获s。 -
考虑到限制,我会采用明显的解决方案,
RefCell。这样,守卫只保留对单元格的共享引用,您可以继续使用它。 play.rust-lang.org/…
标签: rust