在测试中,我有一个辅助函数,该函数可以在不同配置的对象上运行给定方法,其简化版本如下所示:
fn run_method<F>(f: F)
where
F: Fn(&Foo),
{
let to_test = vec![0i32];
to_test
.iter()
.map(|param| {
let foo = Foo(*param);
f(&foo);
})
.for_each(drop);
}
// run_method(Foo::run);
在我添加对测试结构的引用,使其成为“终身注释”(由于缺少适当的术语,我的意思是Foo<'a>
)之前,这种方法一直有效。
现在我得到一个错误,表明我认为Rust不想接受Foo::method
作为可以在任何给定生命周期(即F: for<'a> Fn(&Foo<'a>)
)中使用的函数,这是按要求进行的关闭:
error[E0631]: type mismatch in function arguments
--> src/main.rs:54:5
|
3 | fn run(&self) {
| ------------- found signature of `for<'r> fn(&'r Foo<'_>) -> _`
...
54 | run_method(Foo::run);
| ^^^^^^^^^^ expected signature of `for<'r, 's> fn(&'r Foo<'s>) -> _`
|
note: required by `run_method`
--> src/main.rs:44:1
|
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0271]: type mismatch resolving `for<'r, 's> <for<'t0> fn(&'t0 Foo<'_>) {Foo::<'_>::run} as std::ops::FnOnce<(&'r Foo<'s>,)>>::Output == ()`
--> src/main.rs:54:5
|
54 | run_method(Foo::run);
| ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `run_method`
--> src/main.rs:44:1
|
44 | fn run_method<F>(f: F) where F: Fn(&Foo) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我可以通过避免使用闭包来解决该问题(尽管我不太了解'a
是如何被约束为run_method
的局部对象-不是生命周期参数应该由来电者?):
fn run_method<'a, F>(f: F)
where
F: Fn(&Foo<'a>),
{
let to_test = vec![&0i32];
for param in to_test {
let foo = Foo(param);
f(&foo);
}
}
是否可以解决此问题而无需重写?如果不是,那有什么理由不起作用吗?
完整代码:
struct Foo<'a>(&'a i32);
impl<'a> Foo<'a> {
fn run(&self) {
println!("Hello {}", self.0);
}
}
fn run_method<F>(f: F)
where
F: Fn(&Foo),
{
//same as F: for<'a> Fn(&Foo<'a>) {
let to_test = vec![0i32];
to_test
.iter()
.map(|param| {
let foo = Foo(param);
f(&foo);
})
.for_each(drop);
}
fn main() {
run_method(Foo::run);
}
// This works:
// fn run_method<'a, F>(f: F)
// where
// F: Fn(&Foo<'a>),
// {
// let to_test = vec![&0i32];
// for param in to_test {
// let foo = Foo(param);
// f(&foo);
// }
// }
// The lifetime-less version:
// struct Foo(i32);
// impl Foo {
// fn run(&self) {
// println!("Hello {}", self.0);
// }
// }
//
// fn run_parser_method<F>(f: F)
// where
// F: Fn(&Foo),
// {
// let to_test = vec![0i32];
// to_test
// .iter()
// .map(|param| {
// let foo = Foo(*param);
// f(&foo);
// })
// .for_each(drop);
// }
//
// fn main() {
// run_parser_method(Foo::run);
// }
有关相同错误代码的其他问题的概述:
trait { fn handle<'a>(); }
与impl<'a> { fn handle() {} })
|args| {...}
,没有显式类型注释(|args: &[&str]|
)不被接受为Fn(&[&str]) -> ()
;答案并不能解释原因(后者暗示该政策未在2015年实施)let mut insert = |k| seq.insert(k); (1..10).cycle().take_while(insert)
),这掩盖了更有用的“借入的数据无法存储在其闭包之外”错误。 / li>
答案 0 :(得分:1)
我可以通过避免闭包来解决此问题(尽管我不太了解'如何将a约束为run_method的本地变量-调用者不应该选择生命周期参数吗?)
是的。但是,当您在不使用闭包的情况下重写它时,您也将引用放入了vec!
调用中,因此不再在运行时构造该引用。相反,编译器可以推断to_test
的类型为Vec<&'static i32>
,并且'static
的寿命超过了所有调用者选择的寿命,因此没有冲突。
这无法按预期编译:
let to_test = vec![0i32];
for param in to_test.iter() {
let foo = Foo(param);
f(&foo);
}
有什么理由不起作用吗?
是的,因为run
的类型受Foo
的类型的约束。更具体地说,您有一个由调用方决定的生存期(隐式地,在Foo
的类型中),因此您必须构造一个 that 生存期的Foo
才能调用给定run
参考。
是否可以解决此问题而无需重写?
那要看。
如果所有测试值都是文字,则可以引用'static
。
如果您能够并且愿意重写run
,则可以不受Foo
类型的约束
impl<'a> Foo<'a> {
fn run<'s>(_self: &Foo<'s>) {
println!("Hello {}", _self.0);
}
}
但是它根本不需要进入impl
块。
我认为注释中提供的解决方案是最好的选择,因为考虑到您并不关心具体的Foo<'a>
类型,则无需提供该类型的方法参考。