在Rust中返回可变引用

ffscu2ro  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(78)

我正在学习Rust,所以如果这是一个微不足道的问题,请道歉。我在谷歌上搜索了一个小时,没有结果。
我有一个枚举值数组。我希望在该数组中找到一个匹配特定模式的随机位置,并返回一个对它的可变引用,目的是修改该位置的元素。

enum Tile {
    Empty,
    ...  // Other enum values
}

fn random_empty_tile(arr: &mut [Tile]) -> &mut Tile {
    loop {
        let i = rand::thread_rng().gen_range(0, arr.len());
        let tile = &mut arr[i];
        if let Tile::Empty = tile {
            return tile;
        }
    }
}

字符串
借用检查器在这里抱怨两件具体的事情。第一个是arr.len()调用。这是不允许的,因为它需要对arr进行不可变引用,而我们已经通过参数对arr进行了可变引用。因此,不能采用其他引用,并且不允许调用。
第二个是return tile。这会失败,因为借用检查器无法证明该引用的生存期与arr本身的生存期相同,因此返回该引用是不安全的。
我认为以上对错误的描述是正确的;我想我知道哪里出了问题。不幸的是,我不知道如何解决这两个问题。如果有人能提供一个惯用的解决方案来实现这种行为,将不胜感激。
最后,我希望做到以下几点:

let mut arr = [whatever];
let empty_element = random_empty_tile(&mut arr);
*empty_element = Tile::SomeOtherValue;


从而使数组发生变化,以替换空值。

4jb9z9bj

4jb9z9bj1#

问题的答案

fn random_empty_tile(arr: &mut [Tile]) -> &mut Tile {
    let len = arr.len();
    let mut the_chosen_i = 0;
    loop {
        let i = rand::thread_rng().gen_range(0, len);
        let tile = &mut arr[i];
        if let Tile::Empty = tile {
            the_chosen_i = i;
            break;
        }
    }
    &mut arr[the_chosen_i]
}

字符串
你可以在循环中使用一个可变的borrow,只是不要滥用它,从borrowcheckers的Angular 来看。你实际上做的是可变地重复借用一个数组。和往常一样,编译器是超级有用的,如果你知道如何使用它。
为了找到问题的根源,让我们看看循环的前两次迭代:

fn random_empty_tile_2<'arr>(arr: &'arr mut [Tile]) -> &'arr mut Tile {
   let len = arr.len();

   // First loop iteration
   {
       let i = thread_rng().gen_range(0, len);
       let tile = &mut arr[i]; // Lifetime: 'arr
       if let Tile::Empty = tile {
           return tile;
       }
   } 

   // Second loop iteration
   {
       let i = thread_rng().gen_range(0, len);
       let tile = &mut arr[i]; // Lifetime: 'arr
        if let Tile::Empty = tile {
           return tile;
       }
   }

   unreachable!();


}
编译器告诉我们:arr的借用(称为tile)必须与数组本身(称为'arr)具有相同的生存期。在下一次循环迭代中,我们再次借用arr来替换'arr。这违反了借款人规则。

一些评论

你这样做对你自己没有好处。这可能会在稍后的main中的borrowchecker抱怨中表现出来,当你试图在arr中保存一个值的可变引用并同时使用arr时,就像这样(当然,如果你想一下的话!)不允许。
此外,你选择一个随机的空瓷砖的算法是危险的投机。如果在一个大数组中只有一个空的瓦片怎么办?您的实施将永远。考虑首先过滤指向空图块的所有索引,然后从该集合中选择随机索引,然后返回该索引指向的条目。我不会为这个提供代码,你自己得到了这个:)

相关问题