Borrow checker on parent-child relation

前端 未结 2 1569
南笙
南笙 2021-01-14 17:39

I have the code below producing the error message marked in its comments. I think I understand the message: I want to borrow parent two times: once for finding its child, a

2条回答
  •  温柔的废话
    2021-01-14 17:52

    You are getting the error message for a different reason. You have a non-mutable variable parent and are trying to create a &mut to it. Fixing that you get

    let mut parent = Parent {
        used: 0,
        child: Child {
            dummy: 1
        }
    };
    parent.child.use_parent(&mut parent);
    

    and the corresponding error

    :31:34: 31:40 error: cannot borrow `parent` as mutable more than once at a time
    :31     parent.child.use_parent(&mut parent);
                                               ^~~~~~
    :31:5: 31:17 note: previous borrow of `parent.child` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `parent.child` until the borrow ends
    :31     parent.child.use_parent(&mut parent);
                  ^~~~~~~~~~~~
    :31:41: 31:41 note: previous borrow ends here
    :31     parent.child.use_parent(&mut parent);
                                                     ^
    

    You almost drew the right conclusion.

    I have to prove that Child doesn't disappear when it modifies Parent

    Not quite. You have to prove that you will never have two &mut or one &mut and a & to the child. If you had a &mut to the parent you could use it to get a &mut to the child. Therefor, if you had a &mut to the parent and a &mut to the child, you could get two &mut to the child.


    The only solution I see is to move the use function to the Parent type and access the child through self.

    impl Parent { 
        fn use_parent(&mut self) {
            // use both child and parent
            self.used += self.child.dummy;
            self.child.dummy += 1;
        }
    }
    

    Addressing your comment:

    Unfortunately, the solution applies to this simplified problem, but not to my actual problem. Parent has a vector of children, which might have deeple nested grand children. I can't just say self.child

    Since you shouldn't modify your vector (and can't, Rust protects you), because that would invalidate the reference to the child, you can pass those parts to the function that you need, but none of the parts that are direct parents of the child.

    impl Child { 
        fn use_parent(&mut self, used: &mut i32) {
            // use both child and parent
            *used += self.dummy;
            self.dummy += 1;
        }
    }
    
    fn main() {
        let mut parent = Parent {
            used: 0,
            child: Child {
                dummy: 1
            }
        };
        // although both point to elements of the same structure
        // it is guaranteed at compile-time that they point to
        // non-overlapping parts
        let child = &mut parent.child;
        let used = &mut parent.used;
        child.use_parent(used);
    }
    

    unfortunatly i don't see a way to prove that use_parent's parameters point to parts of the same Parent object. Maybe that could be done with lifetimes, I'm not sure, but I would be immensly interested in that. Note: Rc has the same issue.

提交回复
热议问题