I have a function that accepts a trait as argument wrapped in a Box
use std::fmt::Display;
fn push(e: Box<dyn Display>) {}
push(Box::new(0));
Now I'd like to create another function that accepts an iterator where each Item is of the same type
fn push_batch<I>(batch: I)
where
I: IntoIterator<Item = Box<dyn Display>>,
{
}
push_batch((0..10).map(|i| Box::new(i)));
But doing so results in the following error:
error[E0271]: type mismatch resolving `<[closure@src/main.rs:13:28: 13:43] as FnOnce<({integer},)>>::Output == Box<(dyn std::fmt::Display + 'static)>`
--> src/main.rs:13:5
|
5 | fn push_batch<I>(batch: I)
| ---------- required by a bound in this
6 | where
7 | I: IntoIterator<Item = Box<dyn Display>>,
| ----------------------- required by this bound in `push_batch`
...
13 | push_batch((0..10).map(|i| Box::new(i)));
| ^^^^^^^^^^ expected integer, found trait object `dyn std::fmt::Display`
|
= note: expected struct `Box<{integer}>`
found struct `Box<(dyn std::fmt::Display + 'static)>`
= note: required because of the requirements on the impl of `Iterator` for `Map<std::ops::Range<{integer}>, [closure@src/main.rs:13:28: 13:43]>`
Why does the first example compile while the second doesn't? And how can I create an iterator of boxed traits to pass to the push_batch
function?
Rust does not automatically cast Box<T>
to Box<dyn Trait>
, you must do it explicitly:
push_batch((0..10).map(|i| Box::new(i) as Box<dyn Display>));
What happens in the first case with
push(Box::new(0));
?Rust infers the type to be
Box<dyn Display>
, however the type inference starts to fail for more complicated expressions, especially involving trait bounds.You can also use
Box::new(i) as _
. In this case Rust is smart enough to infer the desired type, it just wants you to spell out the intent.It would be interesting to know if this is on purpose (having to manually specify the intent/cast) in the iterator case, while not having to do so in the first case. And if this is intentional or actually just a limitation of the compiler.