Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Better compiler support for adding lifetime specifiers when returning iterators #54

Open
@helanhalvan

Description

Hi,

I'm not sure if this is the right forum, if not, I'm sorry. Anyway, I had some trouble with lifetime specifiers where the compile errors are a bit strange.

The original code looks like this:

pub fn pos_iter_to_cells(
    pos: impl IntoIterator<Item = Pos>,
    m: &Board,
) -> Vec<Option<(Pos, celldata::CellState)>> {
    let ret = pos
        .into_iter()
        .map(|p @ Pos { x, y }| match m.get(x) {
            Some(v) => match v.get(y) {
                None => None,
                Some(&a) => Some((p, a)),
            },
            None => None,
        })
        .collect();
    return ret;
}

The idea is to take an iterator of positions and return and iterator of positions and their contents, however I couldn't figure out what went wrong when returning an iterator. Just removing the collect and changing the return type leads to:

error[[E0700]](https://doc.rust-lang.org/stable/error_codes/E0700.html): hidden type for `impl IntoIterator<Item = Option<(Pos, CellState)>>` captures lifetime that does not appear in bounds

and recommends adding a lifetime specifier + '_, that addition in turn leads to this error:

error[[E0311]](https://doc.rust-lang.org/stable/error_codes/E0311.html): the associated type `<impl IntoIterator<Item = Pos> as IntoIterator>::IntoIter` may not live long enough

Now, the solution is to ensure pos and m live for at least as long as the return value, which is done by adding lifetime specifiers on the arguments and return value like this:

pub fn pos_iter_to_cells<'a>(
    pos: impl IntoIterator<Item = Pos> + 'a,
    m: &'a Board,
) -> impl IntoIterator<Item = Option<(Pos, CellState)>> + 'a {
    let ret = pos.into_iter().map(|p @ Pos { x, y }| match m.get(x) {
        Some(v) => match v.get(y) {
            None => None,
            Some(&a) => Some((p, a)),
        },
        None => None,
    });
    return ret;
}

However getting there for me required going and asking reddit. It might be that I missed some documentation, not sure. Anyway made a rust-lang-gist with all the types required. Here is the discussion on reddit

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions