使用具有生命周期的参数包装函数时,类型不够通用错误

Type is not generic enough error when wrapping a function with parameters with lifetimes

我在一个外部库中有一个通用的高阶函数,它接受一个 FnMut,包装它,并且 returns 类似于:

fn foo<T>(mut f:impl FnMut(T) -> T) -> impl FnMut(T)-> T{
    move |t|f(t)
}

我决定编写一个包装器来处理特定情况:

fn bar(f:impl FnMut(&str) -> &str) -> impl FnMut(&str) -> &str{
    foo(f)
}

但是,编译器错误地指出其中一种类型不够通用:

error[E0308]: mismatched types
 --> src/main.rs:4:39
  |
1 | fn foo<T>(mut f:impl FnMut(T) -> T) -> impl FnMut(T)-> T{
  |                                        -----------------
  |                                        |
  |                                        the expected opaque type
  |                                        the found opaque type
...
4 | fn bar(f:impl FnMut(&str) -> &str) -> impl FnMut(&str) -> &str{
  |                                       ^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected associated type `<impl FnMut<(&str,)> as FnOnce<(&str,)>>::Output`
             found associated type `<impl FnMut<(&str,)> as FnOnce<(&str,)>>::Output`

如果我使用像 i32 这样没有生命周期的类型,它编译得很好,并且写出 HRTB 不会改变错误。据我所知,编译器无法匹配函数输出的生命周期,但我无法弄清楚为什么会遇到问题以及如何解决它。

Playground

不幸的是,Rust 目前不允许您为您的 bar 示例创建足够通用的 foo

但是如果您修改 bar 以便调用者选择 f 的生命周期,而不是它在所有生命周期中都是通用的,您可以使其与当前的 foo 一起工作:

fn foo<T>(mut f: impl FnMut(T) -> T) -> impl FnMut(T)-> T {
    move |t| f(t)
}

fn bar<'a>(f: impl FnMut(&'a str) -> &'a str) -> impl FnMut(&'a str) -> &'a str {
    foo(f)
}

这在技术上更具限制性,但对于大多数用例来说,它应该是等效的。