我正在尝试根据条件选择要调用的函数。我想将该函数存储在一个变量中,以便稍后可以再次调用它而无需携带条件。这是一个最小的工作示例:
fn foo() {
println! ("Foo");
}
fn bar() {
println! ("Bar");
}
fn main() {
let selector = 0;
let foo: &Fn() = &foo;
let bar: &Fn() = &bar;
let test = match selector {
0 => foo,
_ => bar
};
test();
}
我的问题是:是否可以去掉中间变量?我试过简单地删除它们:
fn foo() {
println! ("Foo");
}
fn bar() {
println! ("Bar");
}
fn main() {
let selector = 0;
let test = match selector {
0 => &foo as &Fn(),
_ => &bar as &Fn()
};
test();
}
但是随后借用检查器提示说借用的值只在匹配结束之前有效(顺便说一句,为什么?函数是'static
无论如何应该有效到时间结束) .我还尝试通过使用 &foo as &'static Fn()
使 'static
生命周期显式化,但这也不起作用。
最佳答案
如果您只需要使用静态函数而不是闭包,则以下方法有效:
fn foo() {
println!("Foo");
}
fn bar() {
println!("Bar");
}
fn main() {
let selector = 0;
let test: fn() = match selector {
0 => foo,
_ => bar
};
test();
}
(试穿playground)
这里我使用了函数类型而不是函数特征。
借来的trait对象不起作用的原因大概有以下几点。任何特征对象都是一个胖指针,由指向某个值的指针和指向虚拟表的指针组成。当 trait 对象从闭包中创建时,一切都很清楚——值将由闭包本身表示(在内部是包含所有捕获变量的结构的实例)并且虚拟表将包含指向实现的指针编译器生成的相应 Fn*()
特征,其主体将是闭包主体。
然而,对于函数,事情就不是那么清楚了。从中创建特征对象没有值(value),因为函数本身应该对应于 Fn()
特征的实现。因此,rustc 可能会生成一个空结构并为其实现 Fn()
,并且此实现直接调用静态函数(不是实际的 Rust,而是接近的东西):
struct SomeGeneratedStructFoo;
impl Fn<()> for SomeGeneratedStructFoo {
type Output = ();
fn call(&self, args: ()) -> () {
foo();
}
}
因此,当通过 fn foo()
创建特征对象时,实际上会引用一个类型为 SomeGeneratedStructFoo
的临时值。然而,这个值是在匹配中创建的,并且只从匹配中返回对它的引用,因此这个值的生命周期不够长,这就是错误的原因。
关于rust - 动态选择要调用的函数,无需中间变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32885446/