I\'ve got one piece of Rust code that compiles and one that\'s very similar that does not.
The one that works:
pub fn do_something(_: Box
You can't coerce a Box<Box<I>>
into a Box<Box<Iterator<Item = f64>>>
, for reasons discussed in this question, but you can coerce the inner Box
:
pub fn do_something(_: Box<Box<Iterator<Item = f64>>>) {}
fn main() {
let iter = Box::new(Box::new(vec![1.0].into_iter()) as Box<Iterator<Item = f64>>);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
do_something(iter);
}
Playground.
This works because a cast is a coercion site. By writing as Box<Iterator<Item = f64>>
, you're hinting to the compiler that it should attempt to make the expression to the left fit that type instead of inferring Box<IntoIter<f64>>
, because once it's wrapped up in the "outer" Box
, you can't change it anymore.
Alternatively (but less clearly), you could make Box::new(...)
a coercion site by explicitly parameterizing Box
:
let iter = Box::<Box<Iterator<Item = f64>>>::new(Box::new(vec![1.0].into_iter()));
Which effectively does the same thing.
To be honest, I'm no expert in Rust at all, but my expectation would have been that both of the snippets you show do not compile. That is because, as you pointed out, Iterator
is a trait and not a type and basically you want do_something
to receive any type which implements Iterator
. Maybe there exists a shortcut such that the compiler can transform the signature into a generic if one of the types is a trait which could be why is sometimes works, but then I'm also not familiar with the Rust language specification enough.
Instead of having do_something
take something of type Iterator
(?) make it a generic of type T
where T
is trait bound.
pub fn do_something<T>(_: Box<Box<T>>)
where T: Iterator<Item = f64> + Send {}
fn main() {
let iter = Box::new(Box::new(vec![1.0].into_iter()));
do_something(iter);
}
Playground
Alternatively, you constrain do_something
entirely to std::vec::IntoIter
and only take parameters of that type.
pub fn do_something(_: Box<Box<std::vec::IntoIter<f64>>>) {}
fn main() {
let iter = Box::new(Box::new(vec![1.0].into_iter()));
do_something(iter);
}
Playground