1

I create a connection type, i.e.

let mut conn = Connection::open("sqlite.db").unwrap();

And then I pass that type to my save_all function along with a vector, like this:

pub fn save_all(conn: &mut Connection,
                vehicles: Vec<Vehicle>) -> Result<(), Error> {
    let tx = conn.transaction()?;
    for v in vehicles {
        let sql: &str =
            "INSERT INTO local_edits (vehicle_id, make, model, color)
                 VALUES (:vehicle_id, :make, :model, :color)";
        let mut statement = tx.prepare(sql)?;
        statement.execute(named_params! {
                ":vehicle_id": v.vehicle_id,
                ":make": v.make,
                ":model": v.model,
                ":color": v.color})?;
    };
    tx.commit()?;
    return Ok(());
}

This code seems to work okay. Is this code actually correct?

If I don't make my conn type &mut Connection in the save_all function, the code doesn't compile for me. It tells me:

Cannot borrow immutable local variable `conn` as mutable

I'm not quite sure how to understand this.

And is the right pattern to pass conn's "reference" to my save_all function?

I don’t want to transfer ownership to this function. I think I just want to let the function borrow the connection.

Beebunny
  • 4,190
  • 4
  • 24
  • 37
  • There are a few questions here, you should probably ask code_review instead of SO. To answer the clearest question: `&mut` doesn't "transfer ownership" but lets the function have a temporary exclusive access to it, which is the usual pattern for connexions and similar resources. – Denys Séguret May 19 '21 at 05:40

1 Answers1

2

Cannot borrow immutable local variable conn as mutable

The mut in &mut Connection is necessary because you are calling transaction on conn which requires a mutable reference. See also the documentation for this API callI which expects a &mut self.

Borrowing vs. transfer of ownership

Borrowing seems like the right way to do this in case you want to re-use the connection later again. If you would transfer ownership of the connection you'd have to return it again as part of the result in order to re-use it later (because of how affine types in rust work). This would be less-ergonomic to work with than just borrowing the connection.

zgerd
  • 1,080
  • 8
  • 17
  • What if I create a struct that has a Connection member and create an impl of that struct with my save_all function. That way, the struct permanently owns the connection. Would that pattern be considered acceptable in Rust?5 – Beebunny May 19 '21 at 07:28
  • @Beebunny Sure. Though your struct's method will need to take `&mut self` in order to be able to use the connection the way you want to. If it took `&self` then the connection would be immutable within that method. – cdhowie May 19 '21 at 07:39
  • Excellent. Thank you! – Beebunny May 19 '21 at 07:43