rust - 无法在闭包内借用 Vec

标签 rust lifetime borrow-checker

我有一个 Unit s 的向量。我正在尝试构建一个名为 Vec<Vec<Unit>>world 变量。在创建瓦片的过程中,我需要知道它知道哪些瓦片是相邻的。

我有一个函数返回与另一个点相邻的点向量 ( (usize, usize) ),我将其转换为迭代器,映射到它,并获取与 world 中该位置关联的实际单位,如果它是那里,或者尚未提交给 world 的当前行。

我需要访问 map 占用的闭包内的那一行,但我还需要稍后访问它。

fn adjacent((x, y): (usize, usize)) -> Vec<(usize, usize)> {
    vec![
        (x+1, y),
        (x-1, y),
        (x, y+1),
        (x, y-1),
    ]
}

struct Unit {
    pub tiles: Vec<Tile>,
}

#[derive(Copy, Clone)]
enum Tile {
    Floor, Wall, Empty
}

fn main() {
    let heightmap = vec![
        vec![3, 3, 3, 3, 3, 3],
        vec![3, 1, 1, 1, 1, 3],
        vec![3, 1, 1, 1, 1, 3],
        vec![3, 1, 1, 1, 1, 3],
        vec![3, 1, 1, 1, 1, 3],
        vec![3, 1, 1, 1, 1, 3],
        vec![3, 3, 3, 3, 3, 3],
    ];
    let (sx, sy) = (5, 5);
    let mut world: Vec<Vec<Unit>> = vec![];
    for y in 0..sy {
        let mut line: Vec<Unit> = vec![];
        for x in 0..sx {
            let mut tiles: Vec<Tile> = vec![];
            let height = heightmap[y][x];
            let adj = adjacent((x, y))
                .iter()
                .map(|&(x, y)| {
                    let list = if y > world.len() {
                        vec![]
                    } else if y == world.len() {
                        line
                    } else {
                        world[y]
                    };

                    if x >= list.len() {
                        Tile::Empty
                    } else {
                        if height as usize >= list[x].tiles.len() {
                            Tile::Empty
                        } else {
                            list[x].tiles[height as usize]
                        }
                    }
                })
                .collect::<Vec<_>>();

            for z in 0..(height as isize - 1) {
                tiles.push(Tile::Wall);
            }
            line.push(Unit {
                tiles: tiles,
            });
        }
        world.push(line);
    }
}

这是 Rust Playground

我宁愿将 unwrap_orget 等结合使用,但这会导致其他临时值错误,而且无论如何都会更复杂,所以上面的代码虽然可能不是最佳的,但尽可能简单得到它,同时仍然重复错误。我发现我在使用 Rust 时遇到的很多错误是因为我正在做的并不是解决它的最佳方法,所以如果有更惯用的方法,我当然想知道。

我试图使 Unit 可克隆(派生 CloneCopy )但 Rust 出于某种原因不允许我这样做,即使它由向量组成,如果它们的成员是可克隆的,则也是如此。

最佳答案

这是您的问题的一个小例子:

fn main() {
    let mut line = vec![1];
    let something_to_iterate_over = vec![true, false, true];

    for _ in 0..2 {
        let _dummy: Vec<_> = something_to_iterate_over
            .iter()
            .map(|&value| {
                let maybe_moved_line = if value { vec![] } else { line };
                () // Don't care about the return value
            })
            .collect();

        line.push(2);
    }
}

错误信息的第一部分是:

error[E0382]: capture of moved value: `line`
 --> src/main.rs:9:67
  |
8 |             .map(|&value| {
  |                  -------- value moved (into closure) here
9 |                 let maybe_moved_line = if value { vec![] } else { line };
  |                                                                   ^^^^ value captured here after move
  |
  = note: move occurs because `line` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait

error[E0382]: use of moved value: `line`
  --> src/main.rs:14:9
   |
8  |             .map(|&value| {
   |                  -------- value moved (into closure) here
...
14 |         line.push(2);
   |         ^^^^ value used here after move
   |
   = note: move occurs because `line` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait

正如错误消息试图传达的那样,代码在 map 调用之后不再拥有变量 line 的所有权,因为所有权已转移到闭包中。

该代码试图将单个 Vec 提供给其他人,同时为自己保留它,而这根本不是所有权的工作方式。我不能把我的车给你,然后继续每天开着它——这不是我开的!

让代码编译的最小更改是停止尝试放弃唯一的,而是根据需要克隆它:

  1. #[derive(Clone)]添加到Unit
  2. 在闭包内克隆 lineworld[y]:line.clone(), world[y].clone ()

这样做之后,代码永远不会放弃 line 的所有权,因此可以在需要时克隆它。

关于rust - 无法在闭包内借用 Vec,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44980895/

相关文章:

rust - 为什么链接生存期仅与可变引用有关?

rust - 特性 `std::borrow::Borrow<char>` 没有为 `&str` 实现

rust - 是否可以在编译时执行自定义程序?

rust - 无法安装Racer : "pub(restricted) syntax is experimental (see issue #32409)"

types - Impl Add 为类型别名元组 (f64, f64)

rust - 从消耗值中计算出生命周期以供引用

rust - 为什么 Valgrind 在稳定版 1.55.0 中*再次*检测不到内存泄漏?

rust - 如何在实现特征时明确指定生命周期?

rust - 为什么借用的字符串字面量可以通过伪造生命周期比其所有者长寿?

rust - 在嵌套的 lambda 中借用局部变量