别名具有生存期的泛型函数?

时间:2018-12-24 17:22:23

标签: rust

我有一个长函数签名,看起来像这样

Fn(&Framegraph<Compiled>, &Blackboard, &mut Allocator<'_>) -> CommandList + 'static

我想为此别名,因为它在多个位置使用:

macro_rules! define_fn {
    (pub type $name: ident = $($tts:tt)*) => {
        pub trait $name: $($tts)* {}
        impl<T> $name for T
        where T: $($tts)* {}
    }
}

define_fn! {
    pub type Foo = Fn(&'_ u32)
}

fn foo_broken<F: Foo>(f: F) {
    f(&4);
}

fn foo_works<F: Fn(&'_ u32)>(f: F){
    f(&4);
}

fn main() {
    foo_works(|i| {
        println!("{}", i);
    });
}

Playground

foo_broken无法编译:

foo_broken(|i| {
    println!("{}", i);
});

我必须添加一个我不想做的显式类型:

foo_broken(|i: &u32| {
    println!("{}", i);
});

是否有更好的方法来对通用函数进行生命周期别名?我想到的唯一实现是将所有内容放入宏中。

1 个答案:

答案 0 :(得分:2)

您可以使用超特性和通用impl在不使用宏的情况下执行此操作。使用上面的示例:

trait Foo<'a>: Fn(&'a u32) {}

impl<'a, T> Foo<'a> for T where T: Fn(&'a u32) {}

fn foo_not_broken<'a>(f: impl Foo<'a>) {
    f(&4);
}

fn main() {
    foo_not_broken(|i| {
        println!("{}", i);
    });
}

使用这种方法,您避免在闭包上指定生存期,而必须愿意根据它们所接收的函数所采用的引用的生存期来对高阶函数进行参数化。

我意识到这是您的宏正在尝试实现的方法;但是,它不能应付额外的生命周期说明符,并且极大地损害了可读性。