在生存期内将非静态可变引用转换为作用域内的静态可变引用

Transmuting non-static mutable reference into static mutable reference inside a scope within the lifetime

提问人:FreD 提问时间:11/15/2023 最后编辑:FreD 更新时间:11/16/2023 访问量:84

问:

以下代码 (playgroung) 适用于 miri,但它没有未定义的行为吗?

use std::thread;

fn f1(x: &'static mut f64) {
    *x += 1.0;
}

fn f2(x: &'static mut f64) {
    *x *= *x;
}

fn f3(x: &'static mut f64) {
    *x = (*x).log10();
}

fn main() {
    let mut a = vec![1.0f64, 9.0, 100.0];
    let funcs = vec![f1, f2, f3];
    let a_mut = a.iter_mut().collect::<Vec<_>>();
    thread::scope(|s| {
        for (x,f) in a_mut.into_iter().zip(&funcs) {
            s.spawn(|| {
                f(unsafe{std::mem::transmute::<_,&'static mut f64>(x)});
            });
        }
    });
    println!("a -> {a:?}");
}

在此代码中,使用转换将非静态可变引用发送到将静态可变引用作为输入的函数。但是,执行被限制在可变引用生存期内的范围内。


(游乐场)类似的问题Fn(&'static mut f64)

use std::thread;

fn f1(x: &'static mut f64) {
    *x += 1.0;
}

fn f2(x: &'static mut f64) {
    *x *= *x;
}

fn f3(x: &'static mut f64) {
    *x = (*x).log10();
}


fn main() {
    let mut a = vec![1.0f64, 9.0, 100.0];
    let funcs = vec![
        &f1 as &(dyn Fn(&'static mut f64) + Send + Sync),
        &f2 as &(dyn Fn(&'static mut f64) + Send + Sync),
        &f3 as &(dyn Fn(&'static mut f64) + Send + Sync)
    ];
    let a_mut = a.iter_mut().collect::<Vec<_>>();
    thread::scope(|s| {
        for (x,f) in a_mut.into_iter().zip(funcs) {
            s.spawn(|| {
                f(unsafe{std::mem::transmute::<_,&'static mut f64>(x)});
            });
        }
    });
    println!("a -> {a:?}");
}


注意:虽然我的问题是关于生命周期的变化,但这个例子有点人为,因为它可以在不变形的情况下重写,正如 Chayim 所提到的,只需定义 、 和 而不是 和 。fn f1(x: &mut f64)fn f2(x: &mut f64)fn f3(x: & mut f64)fn f1(x: &'static mut f64)fn f2(x: &'static mut f64)fn f3(x: &'static mut f64)

Rust 范围 生存期 转换

评论

0赞 Chayim Friedman 11/16/2023
我希望在您的实际用例中有一个实际的原因,因为这里没有。transmute()
0赞 FreD 11/16/2023
谢谢!在我的实际项目中,它是关于期货而不是线程的。正因为如此,我强加了静态引用。但是我仍然在变量的生命周期内执行期货,特别是通过使用 .async-scoped

答:

1赞 Chayim Friedman 11/16/2023 #1

一生永远不会影响行为。不幸的是,据我所知,这在官方没有记录,但这是一般概念。

如果将这些引用交给未知代码,那将是不合理的,但假设所有代码都是已知的,并且在其生命周期之外实际上没有使用引用,这很好。

评论

0赞 FreD 11/16/2023
谢谢,你已经完美地回答了我的问题,尽管我用一个不好的例子来说明它!