我想要一个结构,它包含一个由该结构的用户设置的函数。我想到了这样的事情:
pub struct MyStruct {
some_function: Fn(f64) -> f64
}
然后我想定义一组可以在创建 MyStruct
实例时选取的常量。我这样试过:
pub const SIGMOID: Fn(f64) -> f64 = |x| 1.0 / (1.0 + E.powf(x));
我收到一个编译错误,即 Fn(f64) -> f64
在编译时没有已知的大小,并且出现了使用 dyn
的警告关键词。我不想使用 dyn
关键字,因为会降低性能。我是否必须使用 Box
将该常量放在堆上,或者是否有更轻量级的方法来执行此操作?我认为将其存储在堆上也会降低性能,还是我弄错了?
最佳答案
引用Fn
trait docs :
This trait (
Fn
) is not to be confused with function pointers (fn
).
函数指针不允许您以类似闭包的方式拥有状态。如果您使用的是 sigmoid
函数之类的东西,它是在没有状态的情况下定义的,您可以使用它。如果您使用带状态的闭包,您需要具有某种形式的动态调度或泛型类型,因为您无法命名闭包的类型。
例如,使用 fn
指针:
struct Foo {
my_func: fn(f64) -> f64
}
或者使用动态调度和引用:
struct Foo<'a> {
my_func: &'a dyn Fn(f64) -> f64,
}
或者具有可变状态:
struct Foo<'a> {
my_func: &'a mut dyn FnMut(f64) -> f64,
}
没有生命周期:
struct Foo {
my_func: Box<dyn FnMut(f64) -> f64>
}
I think there's gonna be a performance penalty when storing it on the heap too or am I mistaken here?
是的,由于通过 vtable 的双重间接性,动态调度经常会受到惩罚。 我相信,我不确定,由于缺乏单态化,也会受到惩罚。但是,除非它们是可量化的,否则这些都不重要。
pub const SIGMOID: Fn(f64) -> f64 = |x| 1.0 / (1.0 + E.powf(x));
这可以变成
pub const SIGMOID: fn(f64) -> f64 = |x| 1.0 / (1.0 + E.powf(x));
和fn
pointers实现所有 Fn*
特性:
In addition, function pointers of any signature, ABI, or safety are
Copy
, and all safe function pointers implementFn
,FnMut
, andFnOnce
. This works because these traits are specially known to the compiler.
关于rust - 创建一个具有可交换功能的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58049565/