我正在尝试根据条件选择要调用的函数.我想将该函数存储在一个变量中,这样我以后可以再次调用它而不需要携带条件.这是一个有用的最小例子:
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();
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:是否有可能摆脱中间变量?我试过简单地删除它们:
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();
}
Run Code Online (Sandbox Code Playgroud)
然后借用检查员抱怨借用的价值仅在比赛结束前有效(顺便说一下,为什么?功能'static无论如何都应该有效到期末).我也试过'static通过使用显示生命周期,&foo as &'static Fn()但这也不起作用.
以下工作,如果您只需要使用静态函数而不是闭包:
fn foo() {
println!("Foo");
}
fn bar() {
println!("Bar");
}
fn main() {
let selector = 0;
let test: fn() = match selector {
0 => foo,
_ => bar
};
test();
}
Run Code Online (Sandbox Code Playgroud)
(在操场上试试)
这里我使用了函数类型而不是函数特征.
借用的特征对象不起作用的原因可能如下.任何特征对象都是一个胖指针,它由指向某个值的指针和指向虚拟表的指针组成.当从闭包创建trait对象时,一切都很清楚 - 值将由闭包本身表示(内部是包含所有捕获变量的结构的实例),虚拟表将包含指向实现的实现Fn*()编译器生成的相应特征,其主体将是闭包体.
但是,有了功能,事情就不那么清楚了.创建特征对象没有价值,因为函数本身应该对应于Fn()特征的实现.因此,rustc可能会生成一个空结构并Fn()为它实现,并且这个实现直接调用静态函数(不是实际的Rust,而是接近):
struct SomeGeneratedStructFoo;
impl Fn<()> for SomeGeneratedStructFoo {
type Output = ();
fn call(&self, args: ()) -> () {
foo();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,当创建特征对象时fn foo(),实际上引用了类型的临时值SomeGeneratedStructFoo.但是,此值是在匹配内创建的,并且只会从匹配中返回对它的引用,因此该值的持续时间不够长,这就是错误的含义.