rustmemory-managementdynamic-memory-allocationallocation

How do I cast the elements referred by a slice without heap allocation?


Let's suppose there's an array of parameters that need to be used in SQL query. Each parameter must be a &dyn ToSql,which is implemented already for &str.

The need arises to use the object both as &dyn ToSql and as &str, like in the example down below, where it needs to implement Display in order to be printed out.

let params = ["a", "b"];

// this works but allocates
// let tx_params = &params
//             .iter()
//             .map(|p| p as &(dyn ToSql + Sync))
//             .collect::<Vec<_>>();

// this is ideal, doesn't allocate on the heap, but doesn't work
params.map(|p| p as &(dyn ToSql + Sync));

// this has to compile, so can't just crate `params` as [&(dyn ToSql + Sync)] initially
println!("Could not insert {}", params);

Error:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `str: ToSql` is not satisfied
  --> src/main.rs:14:20
   |
14 |     params.map(|p| p as &(dyn ToSql + Sync));
   |                    ^ the trait `ToSql` is not implemented for `str`
   |
   = help: the following implementations were found:
             <&'a str as ToSql>
   = note: required for the cast to the object type `dyn ToSql + Sync`

error[E0277]: the size for values of type `str` cannot be known at compilation time
  --> src/main.rs:14:20
   |
14 |     params.map(|p| p as &(dyn ToSql + Sync));
   |                    ^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `str`
   = note: required for the cast to the object type `dyn ToSql + Sync`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` due to 2 previous errors

The trait ToSql isn't implemented for str, but it is for &str, however we borrow checked won't let us borrow p here, even though we're not doing anything with the data, except cast it as a new type.

Playground


Solution

  • I agree with @Caesar's take on this, however you actually can do that without heap allocations.

    You can use <[T; N]>::each_ref() for that (this method converts &[T; N] to [&T; N]):

    params.each_ref().map(|p| p as &(dyn ToSql + Sync));
    

    Playground.