I'm trying to make some utility methods which use ranges as iterators. The problem is with the relevant type bounds - the way I've found looks very cumbersome, and I'm not sure if I'm not missing anything.
Basically, the first attempt was something like this:
fn range_id<T>(range: std::ops::Range<T>) -> impl Iterator<Item = T> {
range
}
This expectedly failed:
error[E0277]: the trait bound `T: Step` is not satisfied
--> src/lib.rs:1:46
|
1 | fn range_id<T>(range: std::ops::Range<T>) -> impl Iterator<Item = T> {
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Step` is not implemented for `T`
|
= note: required because of the requirements on the impl of `Iterator` for `std::ops::Range<T>`
help: consider restricting type parameter `T`
|
1 | fn range_id<T: std::iter::Step>(range: std::ops::Range<T>) -> impl Iterator<Item = T> {
| +++++++++++++++++
Following this suggestion, however, doesn't help much - the new code errors again:
error[E0658]: use of unstable library feature 'step_trait': recently redesigned
--> src/lib.rs:1:16
|
1 | fn range_id<T: std::iter::Step>(range: std::ops::Range<T>) -> impl Iterator<Item = T> {
| ^^^^^^^^^^^^^^^
|
(This raises the question of why such suggestion was ever shown on stable... but that's another topic)
Well, we can try to go another way:
use std::ops::Range;
fn range_id<T>(range: Range<T>) -> impl Iterator<Item = T>
where
Range<T>: Iterator<Item = T>,
{
range
}
This code, at least, compiles. However, if we want to do something more tricky...
use std::ops::Range;
fn range_rev<T>(range: Range<T>) -> impl Iterator<Item = T>
where
Range<T>: Iterator<Item = T> + std::iter::DoubleEndedIterator,
{
range.rev()
}
...you see that we have to add yet another type bound. And furthermore, to use this function in any generic context, we'll have to reiterate these bounds again and again:
fn use_range_rev<T>(range: Range<T>) {
// this fails with "T: Step is not implemented",
// unless we again add _both_ `where` clauses
range_rev(range);
}
Is this all an expected thing?