下面的代码(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:?}");
}
在此代码中,使用Transmute将非静态可变引用发送到将静态可变引用作为输入的函数.但是,执行被限制在可变引用的生存期内的范围内.
Fn(&'static mut f64)
(playground)也有类似的问题
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)
.