Rust中的闭包参数存在生命周期问题 [英] Lifetime issues with a closure argument in Rust

查看:121
本文介绍了Rust中的闭包参数存在生命周期问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试使用与下面的(代码9)中的 print 函数完全相同的闭包时,我得到一个错误

I'm getting an error when trying to use a closure that does exactly the same as the print function below (in ln.9)

错误是通常的借入值寿命不足.我试图在操场中复制它,但是我不能.我敢肯定这主要是因为我不太了解这里发生的事情,因此我们将不胜感激.

The error is the usual borrowed value does not live long enough. I've tried to replicate this in the playground but I can't. I'm certain that this is mainly because I don't really understand what's going on here so any help would be really appreciated.

我不明白的是,调用 print 函数和调用 check 闭包之间有什么区别.它们具有完全相同的签名,甚至具有相同的主体.

What I can't understand is what is the difference between calling the print function and calling the check closure. They have exactly the same signature and even the same body.

创建它们的上下文如何影响借阅检查器?对此有什么解决方案?

How does the context in which they were created affect the borrow checker? What would be the solution to this?

extern crate typed_arena;
use typed_arena::Arena;

#[derive(Debug)]
struct AstNode<'a> {
    name: &'a str,
}

fn get_ast<'a>(path: &str, arena: &'a Arena<AstNode<'a>>) -> &'a AstNode<'a> {
   // ...
}

type CheckFn<'a> = dyn Fn(&'a AstNode<'a>);

fn print<'a>(root: &'a AstNode<'a>) {
    println!("{:?}", root);
}

fn it_does_not_have_details_if_all_ok<'a>(file: &str, check: Box<CheckFn<'a>>) {
    let arena = Arena::new();
    let a = &arena;
    let root = get_ast(file, a);
    println!("{:?}", root);
    // Works
    print(root);
    // Produces an error
    check(root);
}   

错误是:

error[E0597]: `arena` does not live long enough
  --> src/main.rs:21:14
   |
21 |     let a = &arena;
   |              ^^^^^ borrowed value does not live long enough
...
28 | }   
   | - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 19:1...
  --> src/main.rs:19:1
   |
19 | fn it_does_not_have_details_if_all_ok<'a>(file: &str, check: Box<CheckFn<'a>>) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

推荐答案

它们具有完全相同的签名,甚至具有相同的主体.

They have exactly the same signature and even the same body.

主体与主题无关,因为类型检查器将函数视为黑盒,仅查看类型.但是,尽管签名可能看起来相同,但事实却并非如此.区别在于寿命参数的绑定方式.

The body is not relevant because the type checker treats functions as a black box, and only looks at types. But, while the signatures may look the same, they are not. The difference is how the lifetime parameter is bound.

print<'a> 的生​​命周期参数'a 被绑定在您所称的点.由于您要传递 root 作为参数,并且 root 是引用,因此您隐式实例化了'a 作为该引用的生命周期.这正是您想要的,因为 root 的生​​存期长于对 print 的调用.

The lifetime parameter 'a of print<'a> is bound at the point that you call it. Since you are passing root as the argument, and root is a reference, you are implicitly instantiating 'a to be the lifetime of that reference. This is exactly what you want because root lives longer than the call to print.

但是在您调用它之前,绑定了 check<'a> 的生​​存期参数'a .而是将其绑定到函数 it_does_not_have_details_if_all_ok<'a> 的生​​命周期参数,该参数由 it_does_not_have_details_if_all_ok 的调用者确定,因此可能是更长的任何生命周期比此函数调用.这绝对不是您想要的,因为:

But the lifetime parameter 'a of check<'a> is bound before you call it. Instead, you have bound it to the lifetime parameter of the function it_does_not_have_details_if_all_ok<'a>, which is determined by the caller of it_does_not_have_details_if_all_ok, so could be any lifetime that is longer than this function call. This is definitely not what you want because:

  1. 引用 root 寿命不长(因为它保存了对函数本地的 arena 的引用).
  2. 函数 check 甚至不需要它的参数就可以使用那么长的时间.
  1. The reference root does not live that long (because it holds a reference to arena which is local to the function).
  2. The function check does not even need its argument to live that long.

这与

This is exactly the same as the reason why you can't return a reference to a variable created in a function. The difference is that you don't actually even need this lifetime constraint.

我无法轻松地对此进行测试,因为您仅发布了代码图像,并且未提供一些定义.但是,快速的解决方法是使用高级特质绑定(HRTB)在 CheckFn 上:

I can't easily test this out because you only posted an image of your code, and you have a few definitions not provided. But the quick fix is to use a higher-ranked trait bound (HRTB) on CheckFn:

type CheckFn = dyn for<'a> Fn(&'a AstNode<'a>);

只要您提到 CheckFn ,就无需绑定'a .相反,生存期是在调用内部函数时绑定的,就像 print 那样.

This gets rid of the need to bind 'a whenever you mention CheckFn. Instead, the lifetimes are bound at the point when the inner function is called, just like it is for print.

正如评论中指出的那样,您可以完全消除这些生存期:

As pointed out in the comments, you can elide these lifetimes altogether:

type CheckFn = dyn Fn(&AstNode);

这将导致类型检查器比上面更普遍地推断寿命:

This will cause the type checker to infer the lifetimes slightly more generally than above:

type CheckFn = dyn for<'a, 'b> Fn(&'a AstNode<'b>);

这篇关于Rust中的闭包参数存在生命周期问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆