社区首页 >问答首页 >无法借用对捕获树中结构的引用,因为它的存留时间不够长

无法借用对捕获树中结构的引用,因为它的存留时间不够长
EN

Stack Overflow用户
提问于 2020-07-31 13:06:44
回答 2查看 139关注 0票数 2

我有一个包含节点和子节点的树结构,以及一个来自GUI库的循环,该循环期望在每次迭代中运行一个函数。我正在努力让借入检查器允许我保留对我正在处理的节点的引用-它抱怨nodes的寿命不够长。

这是一个最小的复制品:

代码语言:javascript
代码运行次数:0
复制
#[derive(Debug)]
struct Node {
    value: u64,
    children: Vec<Node>,
}

fn run_loop<F>(mut handler: F)
where
    F: 'static + FnMut(),
{
    for _ in 0..500 {
        handler();
    }
}

fn main() {
    let nodes = vec![
        Node {
            value: 1,
            children: vec![Node {
                value: 3,
                children: vec![],
            }],
        },
        Node {
            value: 2,
            children: vec![],
        },
    ];
    let mut node = &nodes[0];

    run_loop(move || {
        println!("Node: {:?}", node);
        node = &node.children[0];
    });
}
代码语言:javascript
代码运行次数:0
复制
error[E0597]: `nodes` does not live long enough
  --> src/main.rs:30:21
   |
30 |       let mut node = &nodes[0];
   |                       ^^^^^ borrowed value does not live long enough
31 | 
32 | /     run_loop(move || {
33 | |         println!("Node: {:?}", node);
34 | |         node = &node.children[0];
35 | |     });
   | |______- argument requires that `nodes` is borrowed for `'static`
36 |   }
   |   - `nodes` dropped here while still borrowed

Rust Playground

让它工作的最好方法是什么?我不能改变run_loop的结构。理想情况下,我不会更改Node的结构(它是从第三方库返回的对象,因此虽然我可以将该对象解析为新的数据结构,但这并不优雅)。只需在main中进行更改,我就可以让借阅检查器满意吗

EN

回答 2

Stack Overflow用户

发布于 2020-07-31 14:21:08

它抱怨节点的生存时间不够长。

这是因为它没有,因为run_loop函数需要它的参数永远有效('static)。nodes变量不会永远存在,因此捕获它的闭包也不会永远存在。

简单的解决方法是更改run_loop,使其不需要永久有效的参数(通过删除'static约束),但是如果您不能这样做,那么您可以改为让nodes永久有效。你可以通过“泄露”它来做到这一点。

代码语言:javascript
代码运行次数:0
复制
let nodes = vec![ /*...*/ ];
let nodes = Vec::leak(nodes);
let mut node = &nodes[0];

(Playground link)

目前,这需要每晚进行一次,但在稳定的Box中有类似的泄漏函数。

代码语言:javascript
代码运行次数:0
复制
let nodes = vec![ /*...*/ ];
let nodes = Box::leak(nodes.into_boxed_slice());
let mut node = &nodes[0];

(Playground link)

票数 4
EN

Stack Overflow用户

发布于 2020-08-09 02:43:42

泄漏解决方案不适用于我的实际用例,而且在任何情况下都不能很好地表示情况的语义或进行很好的泛化(如果您不想永远泄漏内容呢?或者,如果它不是您正在使用的向量呢?)。

我最终决定最好的解决方案就是做不安全的指针操作:

代码语言:javascript
代码运行次数:0
复制
let nodes = Box::pin(nodes);
let mut node_ptr = std::ptr::NonNull::from(&nodes[0]);

run_loop(move || {
    let node = unsafe { node_ptr.as_ref() };
    println!("Node: {:?}", node);
    node_ptr = std::ptr::NonNull::from(&(node.children[0]));
});

在我的实际实现中,我将nodesnode_ptr都放在一个结构中,这样就可以保证节点不会在node_ptr之前被删除。

我将把它留下来,因为我很想看到一个不需要unsafe的解决方案,但我在这里发布了这篇文章,因为至少目前它是我最好的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63192441

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文