提问人:FreD 提问时间:11/15/2023 最后编辑:FreD 更新时间:11/16/2023 访问量:84
在生存期内将非静态可变引用转换为作用域内的静态可变引用
Transmuting non-static mutable reference into static mutable reference inside a scope within the lifetime
问:
以下代码 (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)
答:
1赞
Chayim Friedman
11/16/2023
#1
一生永远不会影响行为。不幸的是,据我所知,这在官方没有记录,但这是一般概念。
如果将这些引用交给未知代码,那将是不合理的,但假设所有代码都是已知的,并且在其生命周期之外实际上没有使用引用,这很好。
评论
0赞
FreD
11/16/2023
谢谢,你已经完美地回答了我的问题,尽管我用一个不好的例子来说明它!
评论
transmute()
async-scoped