Immutable borrow inside of loop of mutable borrows

Hi there,
this might be a stupid question but I have not been able to find an answer for this specific issue:

pub fn edit_qm_residues(
    pdb: &mut pdbtbx::PDB,
    qm_val: f64,
    list: Vec<isize>,
    partial: &str,
) -> Result<()> {
    for residue in pdb.residues_mut() {
        for atom in residue.atoms_mut() {
            match partial {
                "None" => {
                    if list.contains(&residue.serial_number()) {
                        atom.set_occupancy(qm_val);
                    }
                }
                &_ => return Err("Passed argument 'partial' not recognized".into()),
            }
        }
    }
    Ok(())
}

So I am doing a nested for loop over mutable references (residue and atom) which is needed because the line atom.set_occupancy(qm_val); modifies a field of the atom struct. However, the borrow checker complains that I try to use an immutable borrow here: &residue.serial_number(). This is a getter for a field in the residue struct which I need because the field is private.
Bottom line: mutable borrow and immutable borrow don't work side by side. I tried cloning residue but this also gets rejected because of an immutable borrow.
I feel like this should be a somewhat common problem, is there an idiomatic way to solve this issue?

What about cloning the serial number?

pub fn edit_qm_residues(
    pdb: &mut pdbtbx::PDB,
    qm_val: f64,
    list: Vec<isize>,
    partial: &str,
) -> Result<()> {
    for residue in pdb.residues_mut() {
        let serial_number = residue.serial_number().clone();
        for atom in residue.atoms_mut() {
            match partial {
                "None" => {
                    if list.contains(&serial_number) {
                        atom.set_occupancy(qm_val);
                    }
                }
                &_ => return Err("Passed argument 'partial' not recognized".into()),
            }
        }
    }
    Ok(())
}

You probably just did it in the wrong order. If you want to clone it, it must happen before the call to atoms_mut(). (or after the inner loop)

Yes of course. I thought it was something obvious but I think I have tunnel vision by now. Cloning before calling atoms_mut() solved it.
Thanks!

1 Like