< 返回版块

jasper2007111 发表于 2024-05-19 16:47

为什么这样标注后,就会存在多次被借用的错误?


struct Person<'a> {
    age: &'a u16
}

impl<'a> Person<'a> {
    fn set_age(&'a mut self, age: &u16) {
        // self.age = age;
    }
}

fn main(){
    let mut p = Person{age:&0};
    p.set_age(&20);
    p.set_age(&30);
}

但是把改成这样后,就又好了。

struct Person<'a> {
    age: &'a u16
}

impl<'a> Person<'a> {
    fn set_age(&mut self, age: &u16) {
        // self.age = age;
    }
}

fn main(){
    let mut p = Person{age:&0};
    p.set_age(&20);
    p.set_age(&30);
}

这个单纯是为了搞清楚Rust的生命周期标注的一个简单例子,之前看《Rust程序设计语言》中关于生命周期确保引用有效一节时感觉能理解,但是这个例子中就有点无法理解,加上'a后就不能多次使用了。

补充:我根据提示查看了下rustc --explain E0499

let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;

给出的例子,我觉得是可以理解的。但是为什么fn set_age(&'a mut self, age: &u16)这个也会导致跟例子一样的问题,这似乎隐藏着某种的东西,给用户一种难以理解的感觉。

评论区

写评论
bestgopher 2024-05-20 17:24

https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md#5-if-it-compiles-then-my-lifetime-annotations-are-correct

liming01 2024-05-20 17:07

你们分析得不对。注意看这是第一段代码报错的信息:

error[E0499]: cannot borrow `p` as mutable more than once at a time
  --> src/main.rs:14:5
   |
13 |     p.set_age(&20);
   |     - first mutable borrow occurs here
14 |     p.set_age(&30);
   |     ^
   |     |
   |     second mutable borrow occurs here
   |     first borrow later used here

For more information about this error, try `rustc --explain E0499`.

我把这段代码转成相似的代码:

struct Person<'a> {
    age: &'a mut u16
}

impl<'a> Person<'a> {
    fn set_age(&'a mut self, age: &'a mut u16) {
        self.age = age;
    }
}

fn main(){
    let mut p = Person{age:&mut 0};
    let a1 = &mut 1;
    let a2 = &mut 2;

    let p1 = &mut p;
    let p2 =&mut p;
    p1.age=a1;
    p2.age=a2;

    // p.set_age(a1);
    // p.set_age(a2);
}

注意此时报错是一样的:

error[E0499]: cannot borrow `p` as mutable more than once at a time
  --> src/main.rs:17:13
   |
16 |     let p1 = &mut p;
   |              ------ first mutable borrow occurs here
17 |     let p2 =&mut p;
   |             ^^^^^^ second mutable borrow occurs here
18 |     p1.age=a1;
   |     --------- first borrow later used here

For more information about this error, try `rustc --explain E0499`.
error: could not compile `test1` (bin "test1") due to 1 previous error

注意: 生命周期‘a表示,使得rust调用函数p.set_age(a1)时,生命周期与p的生命周期一样,我这段代码中的p1和p2的生命周期跟p是一样的,所以报错也相似。

而你的第二段代码,相当于下面,这个能跑。

struct Person<'a> {
    age: &'a mut u16
}

fn main(){
    let mut p = Person{age:&mut 0};
    let a1 = &mut 1;
    let a2 = &mut 2;

    let p1 = &mut p;
    p1.age=a1;
    let p2 =&mut p;
    p2.age=a2;

}
ggggjlgl 2024-05-20 11:55

我的理解和bestgopher差不多,p调用set_age(p.set_age(&20))时,set_age会隐式借入&mut p,当set_age返回时会隐式销毁此&mut p,就是把这个自动创建的可变引用的生命周期限制在函数的{}内。但是你的'a显示地要求了这个可变引用必须与p或者p.age的生命周期强关联,就等于手动禁止了自动销毁&mut p,然后可变引用是独占访问,当你第二次调用时就会违反这个规则。

bestgopher 2024-05-20 09:58

应该是你给mut self标注‘a,表示这个可变借用的生命周期至少和a一样长,而a的生命周期至少和p一样长,而p持续到函数结束,说明mut self也持续到函数结束,因此第二个mut self和第一个mut self冲突了。我是这样理解的。

Bai-Jinlin 2024-05-19 17:28

这个涉及变性的问题比较复杂,以前有人写过帖子 https://rustcc.cn/article?id=38000317-0d25-40b1-aee9-81143322bec4

反正就是记住不要让一个生命周期注解在一个类型中出现多次就好了。

1 共 5 条评论, 1 页