全局变量中的Rust-boxed闭包



我想在全局变量EXPRESSION_FUNCTION中存储一个装箱闭包(Box<dyn Fn(f64, f64) -> f64>(。

以下是我实现这一目标的尝试:

type F2d = Box<dyn Fn(f64, f64) -> f64>;
static mut EXPRESSION_FUNCTION: *mut F2d = 0 as *mut F2d;
fn create_function() -> F2d {
Box::new(|_: f64, _: f64| 0.0)
}
fn set_expression_function() {
unsafe {
EXPRESSION_FUNCTION = Box::into_raw(create_function());
}
}

我得到一个类型不匹配:

error[E0308]: mismatched types
--> srclib.rs:79:45
|
79 |         EXPRESSION_FUNCTION = Box::into_raw(create_function());
|                                             ^^^^^^^^^^^^^^^^^ expected struct `Box`, found trait object `dyn Fn`
|
= note: expected struct `Box<Box<(dyn Fn(f64, f64) -> f64 + 'static)>, _>`
found struct `Box<(dyn Fn(f64, f64) -> f64 + 'static), std::alloc::Global>`

如何将create_function的结果转换为全局变量?

请勿使用static mut使用static mut非常容易编写违反Rust引用和别名规则的错误程序。相反,将static与某种细胞(内部可变类型(一起使用——甚至UnsafeCell(这应该是最后的手段(也比static mut更容易正确使用。

如果您的变量只初始化一次,最简单的解决方案是使用once_cell(它正在被包括在标准库中,但目前是一个广泛使用的第三方库(。

use once_cell::sync::OnceCell;
type F2d = Box<dyn Fn(f64, f64) -> f64 + Send + Sync>;
static EXPRESSION_FUNCTION: OnceCell<F2d> = OnceCell::new();
fn create_function() -> F2d {
Box::new(|_: f64, _: f64| 2.0)
}
fn set_expression_function() {
if let Err(_) = EXPRESSION_FUNCTION.set(create_function()) {
panic!("already set");
}
}
fn main() {
set_expression_function();

let f = EXPRESSION_FUNCTION.get().expect("not set");
assert_eq!(f(10., 0.), 2.0);
}

如果它需要重新分配,那么你需要一个锁。parking_lot::RwLock是一个不错的选择,因为它可以在编译时构建,所以不需要延迟初始化:

use parking_lot::RwLock;
type F2d = Box<dyn Fn(f64, f64) -> f64 + Send + Sync>;
static EXPRESSION_FUNCTION: RwLock<Option<F2d>> = RwLock::new(None);
fn create_function() -> F2d {
Box::new(|_: f64, _: f64| 2.0)
}
fn set_expression_function() {
*EXPRESSION_FUNCTION.write() = Some(create_function());
}
fn main() {
set_expression_function();

let option_fn_guard = EXPRESSION_FUNCTION.read();
let f = option_fn_guard.as_ref().expect("not set");
assert_eq!(f(10., 0.), 2.0);
}

与您开始使用的static mut不同,无论函数和全局变量如何使用,这两个程序都是健全的(不会segfault等(。这是一个很好的Rust编程实践。

我使用Some:使其工作

type F2d = Box<dyn Fn(f64, f64) -> f64>;
static mut EXPRESSION_FUNCTION: Option<F2d> = None;
fn create_function() -> F2d {
Box::new(|x: f64, y: f64| x+y)
}
fn set_expression_function() {
unsafe {
EXPRESSION_FUNCTION = Some(create_function());
}
}
fn main() {
set_expression_function();
unsafe { 
if let Some(f) = &EXPRESSION_FUNCTION{
println!("{}", f(1.0, 2.0));
}
};
}

相关内容

  • 没有找到相关文章

最新更新