The following code fails to compile with:
55 | (":dataset_id", &dataset_id),
| ^^^^^^^^^^^ expected `u32`, found `i32`
pub fn save(&mut self, annotations: Vec<Record>, dataset_id: i32) -> Result<(), Error> {
let mut tx = self.conn.transaction()?;
for record in records {
let json: String = record();
let sql: &str =
"INSERT INTO records (record_id, dataset_id, value)
VALUES (:record_id, :dataset_id, :value)";
let mut statement = tx.prepare(sql)?;
statement.execute(&[
(":record_id", &record.id),
(":dataset_id", &dataset_id),
(":value", "hello world")]);
};
tx.commit()?;
Ok(())
}
And if I remove dataset_id from my SQL statement and comment out the line: (":dataset_id", &dataset_id),
Then it fails to compile with:
56 | (":value", &"hello".to_string()),
| ^^^^^^^^^^^^^^^^^^^^ expected `u32`, found struct `std::string::String`
The argument to
execute
is aP: Params
, i.e. "any type that implementsParams
". The Rust compiler will not make a guess at what specific type you want and then process the argument accordingly. Instead, it will just resolve the type of the argument on its own and then see if it implementsParams
.This is your argument:
On its own, what is the type? It's a reference to an array literal containing three tuples: a
(&str, &u32)
, a(&str, &i32)
, and a(&str, &str)
.Lacking any further information, the compiler guesses that the first element is the canonical one, and thus tries to convert the others accordingly. Thus you get the "cannot convert
&i32
to&u32
" errors.What you need, however, is an array of
(&str, &dyn ToSql)
tuples.So you can do one of two things.
First, explicitly cast the first param value to the right type:
Or second, use the
named_params!
macro thatrusqlite
provides, which is arguably prettier: