当函数调用完成时,为什么可变借用的生命周期没有结束? [英] Why doesn't the lifetime of a mutable borrow end when the function call is complete?

查看:42
本文介绍了当函数调用完成时,为什么可变借用的生命周期没有结束?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为 halite.io 编写一个机器人,并且在理解借用的一些影响时遇到了问题.这是无法编译的代码:

I'm writing a bot for halite.io, and am having issues understanding some of the effects of borrowing. Here is the code that will not compile:

let scanLoc = hlt::types::Location {
    x: oflow(coord.0 + l.x as i32, game_map.width),
    y: oflow(coord.1 + l.y as i32, game_map.width),
};
let scan = game_map.get_site(scanLoc, types::STILL);
if (&scan.owner != id) | (scan.owner != 0u8) {
    let ang = game_map.get_angle(l, scanLoc);
    debug!("angle b/w: {}", ang);
    return (l, 2);
}

这是编译器错误:

error[E0502]: cannot borrow `*game_map` as immutable because it is also borrowed as mutable
   --> src/MyBot.rs:112:27
      |
  110 |             let scan = game_map.get_site(scanLoc, types::STILL);
      |                        -------- mutable borrow occurs here
  111 |             if (&scan.owner != id) | (scan.owner != 0u8) {
  112 |                 let ang = game_map.get_angle(l, scanLoc);
      |                           ^^^^^^^^ immutable borrow occurs here
  ...
  116 |         }
      |         - mutable borrow ends here

这是GameMap 函数和结构的代码:

This is the code for the GameMap functions and struct:

#[derive(Clone, Debug)]
pub struct GameMap {
    pub width: u16, // Number of columns.
    pub height: u16, // Number of rows.
    pub contents: Vec<Vec<Site>>,
}

impl GameMap {
    pub fn in_bounds(&self, l: Location) -> bool {
        // ...
    }
    pub fn get_distance(&self, l1: Location, l2: Location) -> u16 {
        // ...
    }
    pub fn get_angle(&self, l1: Location, l2: Location) -> f64 {
        // ...
    }
    pub fn get_location(&self, l: Location, d: u8) -> Location {
        // ...
    }
    pub fn get_site(&mut self, l: Location, d: u8) -> &mut Site {
        // ...
    }
}

为什么 Rust 会可变地借用函数,即使它借用了函数,它在返回结果时也不会返回借用(结束生命周期),所以以后可以借用?

Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?

推荐答案

编者注:通过引入非词法生命周期.

让我们看一个微小的复制品:

Let's look at a tiny reproduction:

struct Site {
    owner: u8,
}

struct GameMap {
    site: Site,
}

impl GameMap {
    fn do_anything(&self) {}

    fn get_site(&mut self) -> &mut Site {
        &mut self.site
    }
}

fn main() {
    let mut game_map = GameMap {
        site: Site { owner: 0 },
    };
    let site = game_map.get_site();
    game_map.do_anything();
}

error[E0502]: cannot borrow `game_map` as immutable because it is also borrowed as mutable
  --> src/main.rs:22:5
   |
21 |     let site = game_map.get_site();
   |                -------- mutable borrow occurs here
22 |     game_map.do_anything(); // Compiler error!
   |     ^^^^^^^^ immutable borrow occurs here
23 | }
   | - mutable borrow ends here

我们的GameMap 只拥有一个Site,但这已经足够了.对 get_site 的调用 返回一个引用(在这种情况下它恰好是可变的):

Our GameMap only owns a single Site, but that's enough. The call to get_site returns a reference (in this case it happens to be mutable):

fn get_site(&mut self) -> &mut Site

感谢 终身省略,这和

fn get_site<'a>(&'a mut self) -> &'a mut Site

这意味着允许返回的引用指向 GameMap 内部的某些内容(它确实如此).然后我们将该引用保存在一个变量中 - site!

This means that the returned reference is allowed to point to something inside of GameMap (which it does). Then we keep that reference in a variable - site!

这意味着我们不能再使用任何对 game_map 的不可变引用,因为它们可能已经(或将来会)因通过可变变量对地图所做的更改而失效参考:

That means that we can no longer use any immutable references to game_map as they might have been (or will in the future be) invalidated by the changes that can be made to the map through the mutable reference:

  • 在任何给定时间,您都可以拥有一个可变引用或任意数量的不可变引用.
  • 引用必须始终有效.

关于参考和借用的 Rust 编程语言章节

为什么 Rust 会可变地借用函数,即使它借用了函数,它在返回结果时也不会返回借用(结束生命周期),所以以后可以借用?

Why does Rust borrow the function mutably, and even if it is borrowing the function would it not return the borrow (ending the lifetime) when returning the result, so it would be available to borrow afterwards?

Rust 可变地借用了您的 struct,因为您正在调用一个需要可变引用的方法(&mut self).然后该方法返回一个可变引用,将结构的借用转移到返回值.当返回值超出范围时,借用结束.

Rust borrows your struct mutably because you are calling a method that requires a mutable reference (&mut self). That method then returns a mutable reference, transferring the borrow of the struct to the returned value. The borrow ends when the returned value goes out of scope.

那么,你如何解决它?可能最灵活的解决方案是引入一个 scope 来限制可变借用:

So, how do you fix it? Probably the most flexible solution is to introduce a scope to constrain the mutable borrow:

let zhu_li_do_the_thing = {
    let site = game_map.get_site();
    site.owner == 5 || site.owner == 42
};

if zhu_li_do_the_thing {
    game_map.do_anything();
}

另一个是相同的想法,但要求您根本不要将借用存储在变量中.因此,可变借用不会超出该语句:

Another is the same idea, but requires that you never store the borrow in a variable at all. Thus the mutable borrow doesn't last beyond that statement:

if game_map.get_site().owner == 42 {
    game_map.do_anything();
}

惯用的 Rust 代码通常具有方法的 foofoo_mut 变体,用于当您不需要可变性时.如果您需要改变 game_mapsite 的不可变借用仍然未完成,这可能无济于事.

It's common for idiomatic Rust code to have foo and foo_mut variants of a method, for when you don't need mutability. This may not help if you need to mutate game_map while the immutable borrow of site is still outstanding.

fn get_site(&self) -> &Site {
    &self.site
}

fn get_site_mut(&mut self) -> &mut Site {
    &mut self.site
}

let site = game_map.get_site();
if site.owner == 5 || site.owner == 42 {
    game_map.do_anything();
}

另见:

这篇关于当函数调用完成时,为什么可变借用的生命周期没有结束?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆