Type casting for slices?

I'm trying to understand something in https://github.com/SergioBenitez/Rocket/blob/master/examples/raw_sqlite/src/main.rs -- specifically:

 conn.execute("INSERT INTO entries (id, name) VALUES ($1, $2)",
            &[&0 as &dyn ToSql, &"Rocketeer"])
        .expect("insert single entry into entries table");

I think I understand the underlying problem being solved here: A slice can only contain a single type, and essentially what's being passed is an reference to a slice of references. In terms of C what's being constructed is an "array of pointers", but Rust needs needs more strict typing; it needs references to the same type.

  • If I remove the explicit type cast as &dyn ToSql the compiler complains about mixed types ("expected integer, found &str"). This makes sense to me.
  • If I remove the first entry and keep the second (i.e. &[&"Rocketeer"]), it compiles fine.
  • If I remove the second entry and the explicit type cast as &dyn ToSql from the first entry, (i.e. &[&0]), it compiles fine.

I'm a little confused by this. I understand that the explicit type cast can be used to tell the compiler "this is the type I want for the elements of this slice", and it will coerce the following elements if possible.

But why does it still work if I just have one element/type? I assume it's getting the ToSql coercion from somewhere else, but why couldn't it do the same if there are multiple elements?

The method being called there is rusqlite::Connection::execute(), which takes as its third argument something that can be converted to an iterator (P: IntoIterator) that produces something implementing rusqlite::types::ToSql (P::Item: ToSql). Slices implement IntoIterator to produce items of the type stored in the slice. In the example you have there, the elements are being cast to the trait object &dyn ToSql (the second one is implictly coerced when it knows what type you want), which implements ToSql so the call works. In the single element cases you have elements of type &i32 (I think, I'm a little unsure of the rules for integer type inference) and &str, both of which also implement ToSql, so those cases are also fine. In the case with both elements and no type cast, it doesn't know you want a trait object (and it doesn't presume to add the overhead of a trait object if you might not want it), so it leaves the two elements as they are, which don't match in type so you get an error.

2 Likes