HRTB的奇怪行为

Zz *_*Tux 4 rust

我有这个代码:

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) -> i32Fn(&A) -> i32,代码工作.

...
    f: Box<Fn(&A) -> i32>,
...
Run Code Online (Sandbox Code Playgroud)

既然AFn特质的论证,它就是一种类型Higher-Rank lifetime.它不应该受struct的生命周期的影响S<A>.

但为什么不能编译代码1?
我如何解决借款或非借款类型A

edd*_*dyb 5

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,所以目前它实际上并不可用(而且我不知道解决方法).