Search code examples
rustreferenceborrow-checkermutability

error: cannot borrow ... as immutable because it is also borrowed as mutable


I've instantiated a struct result and pass it as mutable ref to another function, that fills this struct with data.

AFTER that, I pass this struct as immutable ref to other functions, to insert the data into a database.

let mut result = indexer::IndexRefreshResultHolder {
            putlist: Vec::new(),
            dellist: Vec::new(),
        };

indexer::refresh_indeces(&mut new_idx_set, old_idx_set_opt, &mut result);

pg::delete_index_rows(&mut tx, &result.dellist).await?;
pg::insert_index_rows(&mut tx, &result.putlist).await?;

Signature of refresh_indeces is like below:

pub fn refresh_indeces<'a>(
    new_idx: &'a mut IndexSet,
    old_idx_opt: Option<&'a mut IndexSet>,
    result: &'a mut IndexRefreshResultHolder<'a>,
) -> Result<(), AppError>

The function takes data from new_idx and old_idx and merges it into result.

Compiler error: cannot borrow 'result.dellist' as immutable because it is also borrowed as mutable. Same for 'result.putlist'.

I understand that since the struct was mutable borrowed to refresh_indeces it can not be made sure, that data changes afterwards.

My question now is: "How can I make the compiler understand, that result is not changed after refresh_indeces was called" or in other words: "How can result passed as immutable ref again after it was passed once as mutable ref?

Thanks for you help.

Playground


Solution

  • Just use a new scope so the &mut is dropped before the other refs need to be used:

    
    let mut result = indexer::IndexRefreshResultHolder {
        putlist: Vec::new(),
        dellist: Vec::new(),
    };
    {
        indexer::refresh_indeces(&mut new_idx_set, old_idx_set_opt, &mut result);
    }
    pg::delete_index_rows(&mut tx, &result.dellist).await?;
    pg::insert_index_rows(&mut tx, &result.putlist).await?;
    

    EDIT: Actually your lifetimes are wrong, since they are enforcing to extend a lifetime for the &mut. You can separate them:

    
    fn refresh_indeces<'a, 'b, 'c>(
        new_idx: &'a mut IndexSet,
        old_idx_opt: Option<&'a mut IndexSet>,
        result: &'b mut IndexRefreshResultHolder<'a>,
    ) -> Result<(), std::io::Error>
    

    Playground

    Also, you are creating some temporary references in your playground that will need fixing. And after that another bunch of fixes about ownership will come too