Reputation: 1521
I'm writing an online algorithm, implemented with a series of functions which take iterators and produce iterators.
When I write the function like thus (the content being more sophisticated but not different in terms of types):
fn decode<'a, T>(input: T) -> impl Iterator<Item = i16> + 'a
where
T: Iterator<Item = &'a u8> + 'a,
{
input.map(|b| i16::from(*b)).filter(|i| *i != 0)
}
See the playground.
However, this makes calling the function unergonomic:
let input: Vec<u8> = vec![1, 2, 3, 0];
let v: Vec<i16> = decode(input.iter()).collect();
I'd prefer to use T: Into<Iterator<...
, but I can't. When I write the signature thus:
fn decode<'a, T>(input: T) -> impl Iterator<Item = i16> + 'a
where
T: Into<Iterator<Item = &'a u8>> + 'a,
I get an error saying that the return type's size is not known at compile time:
error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item=&'a u8> + 'static)` cannot be known at compilation time
--> src/main.rs:1:1
|
1 | / fn decode<'a, T>(input: T) -> impl Iterator<Item = i16> + 'a
2 | | where
3 | | T: Into<Iterator<Item = &'a u8>> + 'a,
4 | | {
5 | | input.into().map(|b| i16::from(*b)).filter(|i| *i != 0)
6 | | }
| |_^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item=&'a u8> + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::convert::Into`
Why is this, and is there a better way?
Upvotes: 1
Views: 315
Reputation: 431689
Use IntoIterator
instead:
fn decode<'a>(input: impl IntoIterator<Item = &'a u8> + 'a) -> impl Iterator<Item = i16> + 'a {
input.into_iter().map(|b| i16::from(*b)).filter(|i| *i != 0)
}
Iterator
is a trait and traits do not have a size. This is why you cannot (yet) write:
fn example(x: Iterator<Item = ()>) {}
error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item=()> + 'static)` cannot be known at compilation time
--> src/lib.rs:1:12
|
1 | fn example(x: Iterator<Item = ()>) {}
| ^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item=()> + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: all local variables must have a statically known size
= help: unsized locals are gated as an unstable feature
Into
is defined as:
pub trait Into<T> {
fn into(self) -> T;
}
Something implementing Into<dyn Iterator>
would have to have the function fn into(self) -> dyn Iterator
, returning a trait. Since there's no size to a trait, it cannot (yet) be returned, stored in a variable, or accepted as an argument.
See also:
Upvotes: 5