【问题标题】:Is there a safe way to temporarily retrieve an owned value from a mutable reference in Rust? [duplicate]是否有一种安全的方法可以从 Rust 中的可变引用中临时检索拥有的值? [复制]
【发布时间】:2021-06-10 08:14:32
【问题描述】:

我正在使用两个独立的函数。

  • 第一个获取结构的拥有实例,然后返回它。
  • 第二个采用可变引用,但需要使用第一个函数。
// This structure is not `Clone`.
struct MyStruct;

fn take_owned(s: MyStruct) -> MyStruct {
    // Do things
    s
}

fn take_mut(s: &mut MyStruct) {
    *s = take_owned(s /* problem */);
}

我想过一个解决方案,但我不确定它是否合理:

use std::ptr;

// Temporarily turns a mutable reference into an owned value.
fn mut_to_owned<F>(val: &mut MyStruct, f: F)
where
    F: FnOnce(MyStruct) -> MyStruct,
{
    // We're the only one able to access the data referenced by `val`.
    // This operation simply takes ownership of the value.
    let owned = unsafe { ptr::read(val) };

    // Do things to the owned value.
    let result = f(owned);

    // Give the ownership of the value back to its original owner.
    // From its point of view, nothing happened to the value because we have
    // an exclusive reference.
    unsafe { ptr::write(val, result) };
}

使用这个功能,我可以做到:

fn take_mut(s: &mut MyStruct) {
    mut_to_owned(s, take_owned);
}

这段代码是否正确?如果没有,有没有办法安全地做到这一点?

【问题讨论】:

  • AFAIK 的主要问题是 take_owned 可能会发生恐慌,在这种情况下,无论您在调用者内部做什么,所有权都不会被返回。
  • 啊,是的。那么使用std::panic::catch_unwind 之类的东西会解决问题吗?

标签: rust unsafe ownership


【解决方案1】:

有人已经在名为 take_mut 的 crate 中实现了您正在寻找的东西。

函数 take_mut::take

pub fn take<T, F>(mut_ref: &mut T, closure: F) 
where
    F: FnOnce(T) -> T, 

允许使用&amp;mut T 所指向的值,就好像它是拥有的一样,只要之后有T 可用。

...

如果关闭出现恐慌,将中止程序。

函数 take_mut::take_or_recover

pub fn take_or_recover<T, F, R>(mut_ref: &mut T, recover: R, closure: F) 
where
    F: FnOnce(T) -> T,
    R: FnOnce() -> T, 

允许使用由&amp;mut T 指向的值,就好像它是拥有的一样,只要之后有T 可用。

...

如果closure 发生恐慌,则将&amp;mut T 替换为recover,然后继续恐慌。

实现基本上就是你所拥有的,加上描述的恐慌处理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 1970-01-01
    • 2019-07-19
    相关资源
    最近更新 更多