8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

Rust 中闭包参数的生命周期问题

Matthias Auswöger 2月前

27 0

当我尝试使用与下面的 print 函数完全相同的闭包时(在 ln.9 中),我遇到了一个错误。错误是通常的借用值存活时间不够长。我试过

下面的函数(在 ln.9 中) print 完全相同的闭包时出现错误

这个错误很常见 borrowed value does not live long enough 。我尝试在中复制这个 playground 错误,但做不到。我确信这主要是因为我不太明白这里发生了什么,所以任何帮助都会非常感谢。

函数和调用 print 有什么区别 check 。它们具有完全相同的签名,甚至相同的主体。

它们被创建的环境如何影响借用检查器?这个问题的解决方案是什么?

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>>) {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
帖子版权声明 1、本帖标题:Rust 中闭包参数的生命周期问题
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Matthias Auswöger在本站《http》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 她们有着一模一样的签名,甚至同样的身材。

    函数体并不重要,因为类型检查器将函数视为黑盒,并且只检查类型。但是,尽管签名可能 看起来 相同,但实际上并非如此。区别在于生命周期参数的绑定方式。

    'a 生命周期参数 print<'a> 在调用时绑定。由于您 root 作为参数传递,并且 root 是引用,因此您隐式实例 'a 化为该引用的生命周期。这正是您想要的,因为它的生命周期 root 比调用 print .

    'a 生命周期参数 check<'a> 调用 之前就 已经绑定了 it_does_not_have_details_if_all_ok<'a> ,该参数由 的调用者确定 it_does_not_have_details_if_all_ok ,因此可以是任何比此函数调用更长的生命周期。这绝对不是你想要的,因为:

    1. 该引用 root 不会存活那么久(因为它保存了对该 arena 函数本地的引用)。
    2. 该函数 check 甚至不需要它的参数存活那么久。

    你不能返回在函数中创建的变量的引用的 原因完全相同 。不同之处在于你实际上甚至不需要这个生命周期约束。

    我无法轻松测试这一点,因为您只发布了代码的图像,并且没有提供一些定义。但快速解决方法是在上使用 更高级别的特征边界 (HRTB) CheckFn :

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

    这样就无需 'a 在每次提到时 CheckFn 。相反,生命周期在调用内部函数时进行绑定,就像 print .

    正如评论中指出的那样,你可以完全省略这些生命周期:

    type CheckFn = dyn Fn(&AstNode);
    

    这将导致类型检查器推断出比上面更普遍的生命周期:

    type CheckFn = dyn for<'a, 'b> Fn(&'a AstNode<'b>);
    
  • 谢谢 Peter!你的建议正如你所描述的那样奏效了!我不知道高级特征界限,我疯狂地试图找到一种方法来改变闭包的界限寿命。我非常感谢你的意见和详尽的解释!:D

  • Ilya 2月前 0 只看Ta
    引用 4

    @robertohuertasm,从 CheckFn 中省略生命周期 (type CheckFn = dyn Fn(&AstNode)) 也应该可行。生命周期省略规则发挥作用,并产生正确的结果。

返回
作者最近主题: