0

I'm trying to implement the 3rd bullet point from chapter 8.3, with a difference that an employee can be added to multiple departments.

#[cfg(test)]
mod company {
    use std::collections::HashMap;

    struct Company<'a> {
        employees: HashMap<String, Employee>,
        departments: HashMap<String, Department<'a>>,
    }

    struct Department<'a> {
        name: String,
        employees: HashMap<&'a str, &'a Employee>,
    }

    struct Employee {
        name: String,
    }

    impl<'a> Company<'a> {
        pub fn new() -> Company<'a> {
            Company {
                employees: HashMap::new(),
                departments: HashMap::new(),
            }
        }

        pub fn add_employee_to_department(&'a mut self, employee: &str, department: &str) {
            let d = self.departments.entry(String::from(department)).or_insert(Department::new(department));
            let e = self.employees.entry(String::from(employee)).or_insert(Employee::new(employee));
            d.employees.entry(&e.name).or_insert(e);
        }
    }

    impl<'a> Department<'a> {
        pub fn new(name: &str) -> Department<'a> {
            Department {
                name: String::from(name),
                employees: HashMap::new(),
            }
        }
    }

    impl Employee {
        fn new(name: &str) -> Employee {
            Employee {
                name: String::from(name),
            }
        }
    }

    #[test]
    fn test_add_employee_to_department() {
        let mut c = Company::new();
        c.add_employee_to_department("Sally", "Sales");
        c.add_employee_to_department("Jim", "Sales");
    }
}

When I compile, I get an error:

error[E0499]: cannot borrow `c` as mutable more than once at a time
  --> src/company.rs:55:9
   |
54 |         c.add_employee_to_department("Sally", "Sales");
   |         ---------------------------------------------- first mutable borrow occurs here
55 |         c.add_employee_to_department("Jim", "Sales");
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |         |
   |         second mutable borrow occurs here
   |         first borrow later used here

If I remove lifetime 'a from add_employee_to_department

        pub fn add_employee_to_department(&mut self, employee: &str, department: &str) {
            let d = self.departments.entry(String::from(department)).or_insert(Department::new(department));
            let e = self.employees.entry(String::from(employee)).or_insert(Employee::new(employee));
            d.employees.entry(&e.name).or_insert(e);
        }

I get a different error:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/company.rs:29:36
   |
29 |             let e = self.employees.entry(String::from(employee)).or_insert(Employee::new(employee));
   |                                    ^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
  --> src/company.rs:27:43
   |
27 |         pub fn add_employee_to_department(&mut self, employee: &str, department: &str) {
   |                                           ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src/company.rs:29:21
   |
29 |             let e = self.employees.entry(String::from(employee)).or_insert(Employee::new(employee));
   |                     ^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined here...
  --> src/company.rs:19:10
   |
19 |     impl<'a> Company<'a> {
   |          ^^
note: ...so that reference does not outlive borrowed content
  --> src/company.rs:30:50
   |
30 |             d.employees.entry(&e.name).or_insert(e);
   |                                                  ^

And if I comment the last line in add_employee_to_department

        pub fn add_employee_to_department(&mut self, employee: &str, department: &str) {
            let d = self.departments.entry(String::from(department)).or_insert(Department::new(department));
            let e = self.employees.entry(String::from(employee)).or_insert(Employee::new(employee));
            //d.employees.entry(&e.name).or_insert(e);
        }

the code compiles and the test runs.

I'm new to Rust and could be wrong here, but it seems the original error (cannot borrow 'c' as mutable more than once at a time) is a bug in the borrow checker when a lifetime used with the first &'a self parameter.

A simpler test shows the same problem. The code below compiles as is, but if I add lifetime 'a to fn update(&'a mut self, value: &'a T), I get the same error: Cannot borrow 'w' as mutable more than once at a time.

Any advise on what I'm doing wrong here would be greatly appreciated!

#[cfg(test)]
mod wrapper {
    struct Wrapper<'a, T> {
        value: &'a T,
    }

    impl<'a, T> Wrapper<'a, T> {
        fn new(value: &T) -> Wrapper<T> {
            Wrapper {
                value,
            }
        }

        fn value(&self) -> &T {
            self.value
        }

        fn update(&mut self, value: &'a T) {
            self.value = value;
        }
    }

    #[test]
    fn test_wrapper() {
        let mut w = Wrapper::new(&12);
        w.update(&14);
        w.update(&16);
        assert_eq!(w.value(), &16);
    }
}
Y2i
  • 3,748
  • 2
  • 28
  • 32
  • 1
    For one `&'a mut Type<'a>` ties a knot with the lifetime constraint solver that causes the borrow to last for the entire life of the object, disallowing other references to be made. And then removing `'a` from the method yields another lifetime error which is because you're trying to make a self-referential struct (`departments.employees` trying to reference `employees` in the same `Company` object). See [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/q/32300132/2189130) – kmdreko Apr 23 '22 at 07:18
  • Thank you @kmdreko! Errors in both cases, `&mut self` and `&'a mut self`, make sense now. – Y2i Apr 23 '22 at 14:44

0 Answers0