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();
}
Run Code Online (Sandbox Code Playgroud)
它编译失败:
error[E0310]: the parameter type `A` may not live long enough
Run Code Online (Sandbox Code Playgroud)
在代码2,我换Fn(A) -> i32到Fn(&A) -> i32,代码工作.
...
f: Box<Fn(&A) -> i32>,
...
Run Code Online (Sandbox Code Playgroud)
既然A是Fn特质的论证,它就是一种类型Higher-Rank lifetime.它不应该受struct的生命周期的影响S<A>.
但为什么不能编译代码1?
我如何解决借款或非借款类型A?
helper即使你删除了所有的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();
}
Run Code Online (Sandbox Code Playgroud)
它不起作用的原因是A"来自外部",而Rust无法推断出你想要的for<'a> S<&'a A>,它甚至不能谈论这种类型.
注意,如果let arg = 333;放在上面let x,这个例子确实编译(因为它推断了arg 具体的引用,而不是a for<'a>).
今天最接近的是具有生命周期参数的特征上的关联类型,例如:
// Emulating `type Type<'a>` by moving `'a` to the trait.
trait Apply<'a> {
type Type;
}
struct Plain<T>(std::marker::PhantomData<T>);
impl<'a, T> Apply<'a> for Plain<T> {
type Type = T;
}
struct Ref<T: ?Sized>(std::marker::PhantomData<T>);
impl<'a, T: ?Sized + 'a> Apply<'a> for Ref<T> {
type Type = &'a T;
}
struct S<A: for<'a> Apply<'a>> {
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
}
impl<A: for<'a> Apply<'a>> S<A> {
fn call<'a>(&self, a: <A as Apply<'a>>::Type) {
println!("Return {:?}", (self.f)(a));
}
}
fn create<A: for<'a> Apply<'a>>(
f: Box<for<'a> Fn(<A as Apply<'a>>::Type) -> i32>,
) -> S<A> {
S { f }
}
fn helper() {
let x = create::<Ref<i32>>(Box::new(|x: &i32| *x * 2));
let arg = 333;
x.call(&arg);
}
fn main() {
helper();
}
Run Code Online (Sandbox Code Playgroud)
但是,事实证明这个编码命中了https://github.com/rust-lang/rust/issues/52812,所以目前它实际上并不可用(而且我不知道解决方法).