Borrowing references to attributes in a struct

前端 未结 2 1210
滥情空心
滥情空心 2020-11-28 16:11

It seems that if you borrow a reference to a struct field, the whole struct is considered borrowed. I\'ve managed to isolate and example of what I want to do. I just want to

相关标签:
2条回答
  • 2020-11-28 16:46

    It's a feature of the language. From the compiler point of view, there is no way for it to know that it's safe to call your set() function while a is borrowed via get().

    Your get() function borrows b mutably, and returns a reference, thus b will remain borrowed until this reference goes out of scope.

    You have several way of handling this:

    1. Separate your two fields into two different structs

    2. Move the code which needs to access both attribute inside a method of B

    3. Make your attributes public, you will thus be able to directly get references to them

    4. Compute the new value before setting it, like this:

      fn main() {
          let a = Box::new(A { i: 47 });
          let mut b = B { a: a, j: 1 };
          let newval = {
              let a_ref = b.get();
              foo(a_ref)
          };
          b.set(newval);
      }
      
    0 讨论(0)
  • 2020-11-28 16:46

    Expanding a bit on Levans' answer

    Move the code which needs to access both attribute inside a method of B

    That might look like this at a first pass:

    impl B {
        fn do_thing(&mut self) {
            self.j = self.a.foo()
        }
    }
    

    However, this hard-codes the call to foo. You could also accept a closure to allow this to be more flexible:

    impl B {
        fn update_j_with_a<F>(&mut self, f: F)
        where
            F: FnOnce(&mut A) -> i32,
        {
            self.j = f(&mut self.a)
        }
    }
    
    // ...
    
    b.update_j_with_a(|a| a.foo())
    

    Separate your two fields into two different structs

    This is also applicable when you have borrowed two disjoint subsets of attributes. For example:

    struct A {
        description: String,
        name: String,
        age: u8,
        money: i32,
    }
    
    impl A {
        fn update_description(&mut self) {
            let description = &mut self.description;
            *description = self.build_description()
            // cannot borrow `*self` as immutable because `self.description` is also borrowed as mutable
        }
    
        fn build_description(&self) -> String {
            format!(
                "{} is {} years old and has {} money",
                self.name,
                self.age,
                self.money
            )
        }
    }
    
    fn main() {}
    

    Can be changed into

    struct A {
        description: String,
        info: Info,
    }
    
    struct Info {
        name: String,
        age: u8,
        money: i32,
    }
    
    impl A {
        fn update_description(&mut self) {
            let description = &mut self.description;
            *description = self.info.build_description()
        }
    }
    
    impl Info {
        fn build_description(&self) -> String {
            format!(
                "{} is {} years old and has {} money",
                self.name,
                self.age,
                self.money
            )
        }
    }
    
    fn main() {}
    

    You can combine these two steps (and I'd say that it's better practice) and move the method onto the inner struct.

    0 讨论(0)
提交回复
热议问题