Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.5k views
in Technique[技术] by (71.8m points)

rust - mutably borrow fields from a mutably borrowed struct

from the borrowing rule:

  • At any given time, you can have either one mutable reference or any number of immutable references.

Below, I have a mutable borrow of the struct Foo (the whole struct), which means I borrow every field of this struct. However, I can have another borrow to its field in demo function. And I suspect I have 2 mutable references to x.a:

#[derive(Debug)]
struct Foo {
    a: i32,
    b: i32,
}

fn demo(foo: &mut Foo) {
    // the `foo` is mutable borrow
    // should have exclusive access to all elements of Foo instance
    // However,
    let bar = &mut foo.a; // second ref to `x.a`
    *bar += 1;
    let baz = &foo.b;

    println!("{:?}", bar);
    println!("{:?}", baz);
}


fn main() {
    let mut x = Foo { a: 10, b: 1 };
    let foo = &mut x;  // ref to x, implies borrowing x.a and x.b
    demo(foo);
}

I know we can have disjoint mutable borrow to a struct binding (split borrow reference), but I'm not sure whether splitting the reference to a struct violates the borrow rule.

clarification: above code can compile. My confusion is that it should not compile due to the aforementioned reason. (playground)


I found this link relevant.

When you are borrowing a structure mutably, you are then free to borrow any of the sub-elements mutably.

But I can't find any doc to support it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The line

let bar = &mut foo.a;

creates a reborrow of the a field of foo. As long as the reborrow is alive, the field can't be accessed via foo.a anymore, but only via bar. After the last use of bar, you can use foo.a again – once the reborrow is released, the original borrow is available again.

Reborrowing is very similar to borrowing itself. While a value is borrowed, you cannot access the original value until the borrow is released. The same happens when reborrowing. This makes sure that at any given time there is only a single active mutable borrow, and the borrowing rules are upheld.

The fact that you are dealing with a struct here is incidental. You can do the same with a mutable borrow to any value, e.g. after

let mut i = 17;
let borrow = &mut i;
let reborrow = &mut *borrow;
*reborrow += 4;
*borrow += 21;

the value of i is 42. This code looks like there are multiple active mutable borrows to i. However, at any given time only one of them can be used. The reborrow is released after it is last used, so the original borrow becomes usable again. If we swap the last two lines in this code, it won't compile anymore, since the reborrow would still be alive when borrow is accessed, which is not allowed.

Unfortunately, the mechanics of reborrowing aren't currently documented in the Rust reference. A related, also not well documented topic are implicit reborrows that happen when a mutable reference is bound to a variable of a type that is already known to be a mutable reference.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...