如何在 Rust Closure 中返回引用

hao*_*oel 4 rust

我有以下 Rust 代码无法编译。

struct Person {
    name : String,
    age : u8,
}


fn main() {
    let p = Person{ name: "Nobody".to_string(), age : 24};

    let age = |p : &Person| p.age;
    let name = |p : &Person | &p.name;

    println! ("name={}, age={}" , name(&p), age(&p));
}
Run Code Online (Sandbox Code Playgroud)

并且编译器给出了以下错误消息。

   Compiling playground v0.0.1 (/playground)
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src/main.rs:11:31
   |
11 |     let name = |p : &Person | &p.name;
   |                               ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 11:16...
  --> src/main.rs:11:16
   |
11 |     let name = |p : &Person | &p.name;
   |                ^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/main.rs:11:31
   |
11 |     let name = |p : &Person | &p.name;
   |                               ^^^^^^^
note: but, the lifetime must be valid for the expression at 2:29...
  --> src/main.rs:13:5
   |
13 |     println! ("name={}, age={}" , name(&p), age(&p));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so type `(&&std::string::String, &u8)` of expression is valid during the expression
  --> src/main.rs:13:5
   |
13 |     println! ("name={}, age={}" , name(&p), age(&p));
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)

我尝试添加name关闭的生命周期。

let name<'a> = |p : &'a Person | -> &'a String { &'a p.name };
Run Code Online (Sandbox Code Playgroud)

但仍然出现编译错误

   Compiling playground v0.0.1 (/playground)
error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<`
  --> src/main.rs:12:13
   |
12 |     let name<'a> = |p : &'a Person | -> &'a String { &'a p.name };
   |             ^ expected one of `:`, `;`, `=`, `@`, or `|`

error: aborting due to previous error
Run Code Online (Sandbox Code Playgroud)

只是想知道如何编写正确的代码。

SCa*_*lla 5

另一种解决方案是为您的闭包提供显式类型。不幸的是,您不能使用它的实际类型,但可以将其转换为函数指针。

请记住,问题在于编译器无法正确推断输出的生命周期与输入的生命周期相关(它可能是此错误的一个实例,但我完全不确定)。我们可以通过明确生命周期来解决这个问题。

struct Person {
    name: String,
    age: u8,
}

fn main() {
    let p = Person {
        name: "Nobody".to_string(),
        age: 24,
    };

    let age = |p: &Person| p.age;
    // Our only changes are right here.
    let name: for<'a> fn(&'a Person) -> &'a String = |p: &Person| &p.name;

    println!("name={}, age={}", name(&p), age(&p));
}
Run Code Online (Sandbox Code Playgroud)

(操场)

事实上,可能比这稍微不那么明确。编译器可以很好地确定输入和输出的类型。这只是它的生命周期有问题。因此,用(playground)替换该行let name: for<'a> fn(&'a _) -> &'a _ = |p: &Person| &p.name;也有效。