生命周期参数和函数指针的问题

win*_*ner 3 rust

考虑这个代码:

struct WithLifetime<'a> {
    s: &'a str
}

impl WithLifetime<'_> {
    fn in_impl(&self) -> bool {
        self.s == "a"
    }
}

fn out_of_impl(wl: &WithLifetime<'_>) -> bool {
    wl.s == "a"
}

fn higher_order(f: fn(&WithLifetime<'_>) -> bool) -> bool {
    let s = "a";
    let wl = WithLifetime { s };
    f(&wl)
}

fn main() {
    higher_order(out_of_impl); // This line compiles
    higher_order(WithLifetime::in_impl); // This line does not
}
Run Code Online (Sandbox Code Playgroud)

最后一行main由于此错误而无法编译:

error[E0308]: mismatched types
  --> src/main.rs:23:18
   |
23 |     higher_order(WithLifetime::in_impl); // This line does not
   |                  ^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
   |
   = note: expected fn pointer `for<'r, 's> fn(&'r WithLifetime<'s>) -> _`
              found fn pointer `for<'r> fn(&'r WithLifetime<'_>) -> _`
Run Code Online (Sandbox Code Playgroud)

至于我可以计算出,in_impl并且out_of_impl应该是完全一样的功能。它们都引用 a WithLifetime,并且不关心该引用的生命周期或WithLifetime实例的生命周期参数。两者都应该是传递给的有效参数higher_order。编译器不同意。

传递in_impl给有什么问题higher_order,为什么编译器不允许这样做?我该怎么做才能将具有生命周期参数的结构上的结构方法传递给高阶函数?

Mih*_*hir 5

首先,让我们找出所有 3 个函数的类型:

fn main() {
    let x: i32 = out_of_impl;
    let x: i32 = WithLifetime::in_impl;
    let x: i32 = higher_order;
}
Run Code Online (Sandbox Code Playgroud)

操场

类型out_of_impl

for<'r, 's> fn(&'r WithLifetime<'s>) -> bool {out_of_impl}
Run Code Online (Sandbox Code Playgroud)

类型WithLifetime::in_impl

for<'r> fn(&'r WithLifetime<'_>) -> bool {WithLifetime::<'_>::in_impl}
Run Code Online (Sandbox Code Playgroud)

类型higher_order

fn(for<'r, 's> fn(&'r WithLifetime<'s>) -> bool) -> bool {higher_order}
Run Code Online (Sandbox Code Playgroud)

higher_order接受一个函数,在该函数中,在调用该函数之前,两个生命周期都未命名。所以它基本上接受一个适用于任何生命周期的函数,'r并且's. out_of_impl满足该标准。

但在这种情况下WithLifetime::in_impl,需要事先知道内在的生命周期for<'r> fn(&'r WithLifetime<'_>)

要通过WithLifetime::in_impl,您需要将其更改为:

fn in_impl<'b, 'c>(abc: &'b WithLifetime<'c>) -> bool {
    abc.s == "a"
}
Run Code Online (Sandbox Code Playgroud)

操场

现在,此函数适用于任何任意生命周期'b'c.


接受in_impl而不改变它,就像@米兰那样,

fn higher_order<'b>(f: fn(&WithLifetime<'b>) -> bool) -> bool {
    let s = "a";
    let wl = WithLifetime { s };
    f(&wl)
}
Run Code Online (Sandbox Code Playgroud)

操场

现在,higher_order有一个类型:

for<'b> fn(for<'r> fn(&'r WithLifetime<'b>) -> bool) -> bool {higher_order}
Run Code Online (Sandbox Code Playgroud)

它接受一个函数,其中生命周期'r仅在函数被调用并且提前'b知道时才定义。

这是有效的,out_of_impl因为它接受任何任意生命周期。也适用于,in_impl因为现在签名匹配higher_order.

for<> 语法与常规生命周期界限有何不同?对 HRTB 有很好的解释。