use std::fmt::Debug;
struct S<A>
where
for<'a> A: Debug + 'a,
{
f: Box<Fn(A) -> i32>,
}
impl<A> S<A>
where
for<'a> A: Debug + 'a,
{
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A>
where
for<'a> A: Debug + 'a,
{
S::<A> { f }
}
fn helper() {
let x = create::<&i32>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
let x = helper();
}
编译失败:
error[E0310]: the parameter type `A` may not live long enough
在code 2中,我将Fn(A) -> i32
更改为Fn(&A) -> i32
,代码起作用了。
...
f: Box<Fn(&A) -> i32>,
...
由于A
是Fn
特征的参数,因此它是具有Higher-Rank lifetime
的类型。不应受结构S<A>
的生存期影响。
但是为什么不能编译代码1?
对于借用或非借用类型A
,我该如何解决?
答案 0 :(得分:5)
即使删除所有helper
边界(只有进一步限制什么类型{{1} },而您想允许更多)。
这很简单,我可以举一个例子:
for<'a> A: Debug + 'a,
之所以不起作用,是因为A
是“从外面来的”,Rust无法推断出您想要struct S<A> {
f: Box<Fn(A) -> i32>,
}
impl<A> S<A> {
fn call(&self, a: A) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A> {
S { f }
}
fn helper() {
let x = create(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
,甚至不能谈论这种类型。
请注意,如果将A
放在for<'a> S<&'a A>
上方,则此示例可以编译(因为它会推断出对let arg = 333;
的引用,而不是let x
)。
您今天可以获得的最接近的特征是具有寿命参数的特征的关联类型,例如:
arg
但是,事实证明,这种编码符合https://github.com/rust-lang/rust/issues/52812,因此目前实际上不可用(而且我不知道解决方法)。
答案 1 :(得分:-1)
{@ 3}因为@eddyb的工作原理不起作用,
是 它包含未定义的行为 。但是至少目前它可以正常工作。
use std::fmt::Debug;
struct S<A>
where
A: Debug + Sized,
{
f: Box<Fn(A) -> i32>,
}
impl<A> S<A>
where
A: Debug + Sized,
{
fn call<T>(&self, a: T)
where
T: Debug + Sized,
{
// assert_eq!(std::any::TypeId::of::<A>(), std::any::TypeId::of::<T>()); Not work because TypeId requires 'static lifetime
// If TypeId::of supports non-static lifetime, we also need a compile-time type assert for better error message
println!(
"Return {:?}",
unsafe {
let b = std::mem::transmute::<&Box<Fn(A) -> i32>, &Box<Fn(T) -> i32>>(&self.f);
let ret = b(a);
std::mem::forget(b);
ret
}
);
}
}
fn create<A>(f: Box<Fn(A) -> i32>) -> S<A>
where
for<'a> A: Debug + 'a,
{
S::<A> { f }
}
fn helper() {
let x = create::<&i32>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
x.call(&arg);
x.call(&arg);
}
fn main() {
helper();
}