最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

I am having trouble with rust lifetimes - Stack Overflow

programmeradmin4浏览0评论

.rs

This is the link to the sample repo. I couldn't create a playground because the needed crate is not available on the playground.

I get the following error on line 27.

add explicit lifetime \'a` to the type of `cmds`: `&'a mut bumpalo::collections::Vec<'a, Command<'a>>``

If I do what it is saying me to do. I get more errors in the main function.

\cmds` does not live long enough borrowed value does not live long enough`

What i am trying to do in the action_recursive function is, I am creating a vec which will act like a stack. i will insert all the Commands i have encountered and then do some stuff.

use bumpalo::{collections::Vec, Bump};

enum Command<'a> {
    Add(Vec<'a, Command<'a>>),
    Sub(Vec<'a, Command<'a>>),
    Break,
}

fn main() {
    let arena = Bump::new();
    let mut cmds = Vec::new_in(&arena);
    action(&arena, &mut cmds);
}

fn action<'a>(arena: &'a Bump, cmds: &mut Vec<'a, Command<'a>>) {
    let mut cmd_stack = Vec::new_in(arena);
    action_recursive(arena, cmds, &mut cmd_stack);
}

fn action_recursive<'a>(
    arena: &'a Bump,
    cmds: &mut Vec<'a, Command<'a>>,
    cmd_stack: &mut Vec<'a, Vec<'a, &Command<'a>>>,
) {
    let mut breaks = Vec::new_in(arena);

    cmds.iter().for_each(|cmd| {
        if matches!(cmd, Command::Break) {
            breaks.push(cmd)
        }
    });

    cmd_stack.push(breaks)
}

https://github/Aaditya-23/rust-error/blob/main/src/main.rs

This is the link to the sample repo. I couldn't create a playground because the needed crate is not available on the playground.

I get the following error on line 27.

add explicit lifetime \'a` to the type of `cmds`: `&'a mut bumpalo::collections::Vec<'a, Command<'a>>``

If I do what it is saying me to do. I get more errors in the main function.

\cmds` does not live long enough borrowed value does not live long enough`

What i am trying to do in the action_recursive function is, I am creating a vec which will act like a stack. i will insert all the Commands i have encountered and then do some stuff.

use bumpalo::{collections::Vec, Bump};

enum Command<'a> {
    Add(Vec<'a, Command<'a>>),
    Sub(Vec<'a, Command<'a>>),
    Break,
}

fn main() {
    let arena = Bump::new();
    let mut cmds = Vec::new_in(&arena);
    action(&arena, &mut cmds);
}

fn action<'a>(arena: &'a Bump, cmds: &mut Vec<'a, Command<'a>>) {
    let mut cmd_stack = Vec::new_in(arena);
    action_recursive(arena, cmds, &mut cmd_stack);
}

fn action_recursive<'a>(
    arena: &'a Bump,
    cmds: &mut Vec<'a, Command<'a>>,
    cmd_stack: &mut Vec<'a, Vec<'a, &Command<'a>>>,
) {
    let mut breaks = Vec::new_in(arena);

    cmds.iter().for_each(|cmd| {
        if matches!(cmd, Command::Break) {
            breaks.push(cmd)
        }
    });

    cmd_stack.push(breaks)
}
Share Improve this question asked Mar 19 at 18:09 Aadi-23Aadi-23 72 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

You've attempted to scatter-shot the lifetimes at action_recursive to satisfy the compiler. Which to be honest often works, but you have a net of lifetimes that are interconnected and just using 'a for all of them unfortunately ties them in knots. The big foul is that 'a on the right-hand side of a &mut makes it invariant which means the compiler can't manipulate it as well as other contexts.

Often it is better to leave everything as inferred and fill-in the blanks when the compiler get fussy. But the error suggestions here are a bit ambitious so we'll have to use our brains.

Our first link needs to tie the arena to the breaks that we are putting in cmd_stack:

fn action_recursive<'a>(
    arena: &'a Bump,
         // \------------------------------\
    cmds: &'_ mut Vec<'_, Command<'_>>, // |
                             // v----------/
    cmd_stack: &mut Vec<'_, Vec<'a, &'_ Command<'_>>>,
)

Our next link is to bind the lifetime from cmds to where it is stored in cmd_stack:

fn action_recursive<'a, 'b>(
    arena: &'a Bump,
    cmds: &'b mut Vec<'_, Command<'_>>,
        // \-------------------------v
    cmd_stack: &mut Vec<'_, Vec<'a, &'b Command<'_>>>,
)

And out last link is to simply communicate that the lifetime within the Commands are the same:

fn action_recursive<'a, 'b, 'c>(
    arena: &'a Bump,
    cmds: &'b mut Vec<'_, Command<'c>>,
                               // \-------------v
    cmd_stack: &mut Vec<'_, Vec<'a, &'b Command<'c>>>,
)

And you'll find that it compiles.

The key disconnect here is that we don't want the top level Vec<'_, ...> lifetimes to be bound to arena. We don't actually care about how long they are using the arena. But the reason it was a problem is that Bumpalo's Vec requires that the elements outlive the arena:

pub struct Vec<'bump, T: 'bump>

This can still allow the arena to store shorter-lived values, but only if we allow the compiler to shorten the reference to the arena (immutable references are naturally covariant). As mentioned above, if we left those all connected then the arena would be forced to have its original lifetime and thus not allow shorter-lived references within itself.

Note that other arenas may not have this limitation: your code nearly-verbatim mapped converted to the bump-scope crate will compile since there is no link between elements and the arena lifetime there.

发布评论

评论列表(0)

  1. 暂无评论