一个游戏的最小例子,玩家拥有一个位置,并随着时间的推移而行走.以下内容进行了编译:

use std::thread::sleep;
use std::time::Duration;

struct Player {
    position: usize,
}

impl Player {
    fn new() -> Self {
        Self { position: 0 }
    }
}

impl Player {
    fn get_position(&self) -> usize {
        self.position
    }
}

impl Player {
    fn walk(&mut self) {
        self.position += 1;
    }
}

fn main() {
    let mut player = Player::new();
    loop {
        player.walk();
        sleep(Duration::from_secs(1));
    }
}

如果球员borrow 而不是拥有这个位置,它不会编译:

use std::thread::sleep;
use std::time::Duration;

struct Player<'a> {
    position: &'a mut usize,
}

impl<'a> Player<'a> {
    fn new(position: &'a mut usize) -> Self {
        Self { position }
    }
}

impl<'a> Player<'a> {
    fn get_position(&'a self) -> usize {
        *self.position
    }
}

impl<'a> Player<'a> {
    fn walk(&'a mut self) {
        *self.position += 1;
    }
}

fn main() {
    let mut position = 0;
    let mut player = Player::new(&mut position);
    loop {
        player.walk();
        sleep(Duration::from_secs(1));
    }
}

错误为:

error[E0499]: cannot borrow `player` as mutable more than once at a time
  --> src/main.rs:30:9
   |
30 |         player.walk();
   |         ^^^^^^
   |         |
   |         `player` was mutably borrowed here in the previous iteration of the loop
   |         first borrow used here, in later iteration of loop

我不明白为什么第二个程序不能编译,而第一个程序可以.我知道编译器不接受多个可变borrow ,但第一个不也是这样吗?该程序运行walk函数,该函数要求对self的可变引用,与第二个程序的方式相同.

在这样的情况下,程序需要borrow struct 中的数据,然后修改它,什么是好的解决方案?

推荐答案

这是一个常见的错误

impl<'a> Player<'a> {
    fn walk(&'a mut self) {

生命的名字有意义.因为您在 struct 和方法中使用相同的生存期,所以您告诉编译器,调用walk将为'aborrow Player<'a>,这是Player所borrow 事物的生存期.因此,您是在告诉编译器,调用此方法borrow struct 的时间比 struct 可以存在的时间更长(可调,因此不共享),基本上将您完全锁在 struct 之外.

解决方案很简单,只需删除方法中的解决方案:

impl<'a> Player<'a> {
    fn walk(&mut self) {

现在Rust可以创建第二个生命周期(你可以显式地命名,只要它不是'a),并且它推断that生命周期只有函数体的长度,因为没有任何东西逃逸.

事实上,因为您不需要主动使用'a,所以您也可以将它保留为未命名的,您仍然必须传递它,因为Player是生存期内的泛型,您不能只是省略类型参数,但编译器对此非常满意

impl Player<'_> {
    fn walk(&mut self) {

Rust相关问答推荐

如何使用Match比较 struct 中的值

默认特征实现中的生命周期问题

可以为rust构建脚本编写单元测试吗?

如何在函数中返回自定义字符串引用?

将一个泛型类型转换为另一个泛型类型

解析程序无法在Cargo 发布中 Select 依赖版本

什么时候使用FuturesOrdered?

这是什么:`impl Trait for T {}`?

Rust 1.70 中未找到 Trait 实现

有什么办法可以追踪泛型的单态化过程吗?

Rust 中的生命周期:borrow 的 mut 数据

为什么可以在迭代器引用上调用 into_iter?

Rust 引用元组和引用元组

为什么允许重新分配 String 而不是 *&String

通用函数中的生命周期扣除和borrow (通用测试需要)

当特征函数依赖于为 Self 实现的通用标记特征时实现通用包装器

制作嵌套迭代器的迭代器

在同一向量 Rust 中用另一个字符串扩展一个字符串

守卫如何影响匹配语句?

您不能borrow 对只读值的可变引用