Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method tries to borrow &mut to entire struct, when only a field is required #51421

Closed
acgaudette opened this issue Jun 7, 2018 · 2 comments
Closed

Comments

@acgaudette
Copy link

Offending code:

struct MyStruct {
    usizes: Vec<usize>,
    string: String,
}

impl MyStruct {
    fn new() -> MyStruct {
        MyStruct {
            usizes: Vec::new(),
            string: "string".into(),
        }
    }
    
    fn modify_string(&mut self) {
        self.string = "".into();
    }
}

fn main() {
    let mut my_struct = MyStruct::new();
    
    for _ in &my_struct.usizes {
        my_struct.modify_string();
    }
}

Error:

error[E0502]: cannot borrow `my_struct` as mutable because `my_struct.usizes` is also borrowed as immutable
  --> src/main.rs:23:9
   |
22 |     for _ in &my_struct.usizes {
   |               ----------------
   |               |              |
   |               |              immutable borrow ends here
   |               immutable borrow occurs here
23 |         my_struct.modify_string();
   |         ^^^^^^^^^ mutable borrow occurs here

Playground:
https://play.rust-lang.org/?gist=d55dab3abe961e27cb7aabc66d857687&version=stable&mode=debug

One way this can be fixed is with the following code:

struct MyStruct {
    usizes: Vec<usize>,
    string: String,
}

impl MyStruct {
    fn new() -> MyStruct {
        MyStruct {
            usizes: Vec::new(),
            string: "string".into(),
        }
    }
    
    fn better_modify_string(string: &mut String) {
        *string = "".into();
    }
}

fn main() {
    let mut my_struct = MyStruct::new();
    
    for _ in &my_struct.usizes {
        MyStruct::better_modify_string(&mut my_struct.string)
    }
}

Playground:
https://play.rust-lang.org/?gist=dede523e37dd2894a74b5364d36e6fbf&version=undefined&mode=undefined

Or by breaking the struct apart. I don't think either of those solutions feel very nice. However, I understand that semantically a &mut borrow should mean that the entire struct is off-limits.

Possibly related to #19004

@jonas-schievink
Copy link
Contributor

This is working as intended. It might be possible to add syntax for specifying that only a subset of self is required by the method, but that would require an RFC (I've seen a feature like this discussed before).

(An alternative could be to analyze the body of modify_string, but then you could break other code by changing its body. This is really something that wants to be in the method signature.)

#19004 is potentially different, because closures are contained within the function that creates them. The problem discussed there is similar to how let _ = (&mut x.a, &mut x.b); currently works, but not if one of the fields is borrowed inside a closure.

@oli-obk
Copy link
Contributor

oli-obk commented Jun 8, 2018

This is tracked in rust-lang/rfcs#1215 and does indeed require an RFC

@oli-obk oli-obk closed this as completed Jun 8, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants