Type alias introduces error: "cast requires that `*variable*` is borrowed for `'static`"

Viewed 116

I'm working on a roguelike visibility function. I want to pass in a predicate to determine if the tile is blocking vision or not. The following code works as expected:

fn compute_visible_tiles(
    x: i32,
    y: i32,
    range: i32,
    pred: &dyn Fn(i32, i32) -> bool,
) -> Vec<(i32, i32)> {
    let mut visible: Vec<(i32, i32)> = Vec::new();
    let mut pos_x = x;
    let pos_y = y;

    while pred(pos_x, pos_y) && manhattan_dist(x, y, pos_x, pos_y) < range {
        visible.push((pos_x, pos_y));

        // generate new position to check
        pos_x += 1;
    }

    visible
}

pub fn run() {
    let map = new_square_map();

    let tiles = compute_visible_tiles(2, 3, 2, &|x, y| !map.is_blocking(x, y));
    println!("num tiles visible: {:?}", tiles.len());
}

However, the function signature is a bit ugly, so I wish to introduce a type alias for the predicate, XYPredicate. But doing this introduces an error.

type XYPredicate = dyn Fn(i32, i32) -> bool;

fn compute_visible_tiles(
    x: i32,
    y: i32,
    range: i32,
    pred: &XYPredicate,
) -> Vec<(i32, i32)> {
    let mut visible: Vec<(i32, i32)> = Vec::new();
    let mut pos_x = x;
    let pos_y = y;

    while pred(pos_x, pos_y) && manhattan_dist(x, y, pos_x, pos_y) < range {
        visible.push((pos_x, pos_y));

        // generate new position to check
        pos_x += 1;
    }

    visible
}

pub fn run() {
    let map = new_square_map();

    let tiles = compute_visible_tiles(2, 3, 2, &|x, y| !map.is_blocking(x, y));
    println!("num tiles visible: {:?}", tiles.len());
}


error[E0597]: `map` does not live long enough
  --> src/lib.rs:79:57
   |
79 |     let tiles = compute_visible_tiles(2, 3, 2, &|x, y| !map.is_blocking(x, y));
   |                                                ---------^^^------------------
   |                                                ||       |
   |                                                ||       borrowed value does not live long enough
   |                                                |value captured here
   |                                                cast requires that `map` is borrowed for `'static`
80 |     println!("num tiles visible: {:?}", tiles.len());
81 | }
   | - `map` dropped here while still borrowed

Here is a playground link to the problematic code.

Would someone be kind enough to explain to why using a type alias causes the borrowed map to outlive its scope? And what the proper syntax would be for my type alias in order to fix this error?

1 Answers

This is due to lifetime elision. The default lifetime in the function case (a unique lifetime per parameter) is different than the default lifetime in the type case ('static). You need to be explicit that the lifetime is not static:

type XYPredicate<'a> = dyn Fn(i32, i32) -> bool + 'a;

The normal elision rules will then apply, and 'a will be assigned its own lifetime in the function call.

Related