这个例子颠覆了我对所有权和参考范围的理解

This example subverts my understanding of ownership and reference scope

提问人:杨尚山 提问时间:8/30/2023 最后编辑:E_net4杨尚山 更新时间:8/30/2023 访问量:71

问:

// print:
//  string-a
//  string-aaabc
fn main() {
    let mut a = String::from("string-");
    
    let s = &mut a;
    
    let ss = &mut a; // s goes out of scope here
    ss.push('a');
    // string-a
    println!("{}", ss.clone()); // ss.clone() ==> borrow shared reference, ss(mutable reference) should be gone out of scope. but it still available. why ???
    ss.push_str("aa"); 
    
    let b = &mut (*ss); // borrow '&mut (*ss)' twice to mutable, ss shoudle be gone out of scope. but it still available. why ???
    // uncommenting,error(cannot borrow `*ss` as mutable more than once at a time)
    //      let b = &mut (*ss); ==> first mutable borrow occurs here  ==> why?
    //      ss.push('d'); ==> second mutable borrow occurs here  ==> why?
    //      b.push('b'); ==> first borrow later used here
    // why ? 
    // ss.push('d');
    
    b.push('b');
    ss.push('c'); // why? ss still available!

    println!("{}", a); // string-aaabc
}

这个例子颠覆了我对所有权和引用范围的理解。我很困惑。 问题就像代码注释

Rust 范围 可变 所有权

评论

0赞 prog-fh 8/30/2023
这个关于非词汇生存期详细答案可能会有所帮助。

答:

1赞 Jmb 8/30/2023 #1
// print:
//  string-a
//  string-aaabc
fn main() {
    let mut a = String::from("string-");
    
    let s = &mut a;
    
    let ss = &mut a; // s goes out of scope here
    ss.push('a');
    // string-a
    println!("{}", ss.clone()); // ss.clone() ==> borrow shared reference, ss(mutable reference) should be gone out of scope. but it still available. why ???

ss.clone借款,它不占有所有权。当归还时,它会释放借款,因此仍然可用。事实上,它是排他性引用 () 而不是共享引用 (),这不会改变任何内容。这只意味着在归还之前没有人可以使用,这无论如何都是不可能的。ssclonessss&mut&ssclone

    ss.push_str("aa"); 
    
    let b = &mut (*ss); // borrow '&mut (*ss)' twice to mutable, ss shoudle be gone out of scope. but it still available. why ???

这称为再借。此时:

  • a被 独家借用,所以在掉落之前不能使用。ssass
  • ss被 独家借用,所以在掉落之前不能使用。请注意,仅由 借,而不是移动,因此一旦释放借用,将再次可用。bssbssbssb
    // uncommenting,error(cannot borrow `*ss` as mutable more than once at a time)
    //      let b = &mut (*ss); ==> first mutable borrow occurs here  ==> why?
    //      ss.push('d'); ==> second mutable borrow occurs here  ==> why?
    //      b.push('b'); ==> first borrow later used here
    // why ? 
    // ss.push('d');

b还活着,并且持有 的独家借用,因此无法直接访问。ssss

    b.push('b');

这是我们最后一次使用 ,因此由于非词法生存期,现在可以删除,并再次可用。bbss

    ss.push('c'); // why? ss still available!

b只是借来的,它没有所有权。因此,现在它已经被放弃了,借款被释放并再次可用。出于完全相同的原因,一旦被删除,下一行再次可用:ssbssass

    println!("{}", a); // string-aaabc
}
0赞 fwqaaq 8/30/2023 #2
  1. 首先,变体和引用是两个不同的东西。一般来说,当你使用完一个变体时,rust 会自动为你删除该变量。

    let s = &mut a; // s dropped, because it's not used afterwards.
    
  2. clone:仅供参考ss

  3. let b = &mut (*ss);在这里,您不是借用变量,而是获取原始引用,即保存的原始指针元数据:ssass

    b  --> &mut a
    ss --> &mut a 
    
    • 但是,当您使用可变借用时,可能会出现问题。
     let b = &mut (*ss); // -------
                         //        |
     b.push('b');        //   ------
     // variant `b` was dropped
     // in here, you can just use `ss`
    

如果你把它写成这样,这让你感到困惑,那么

//...
 ss.push('c'); // cannot borrow `*ss` as mutable more than once at a time second mutable borrow occurs hererustcClick for full compiler diagnostic

 b.push('b'); // `b` was not dropped
//...