I have two operators over an Iterator
(playground)
fn begins_with<'a, I>(lines: I, query: &'a str) -> impl Iterator<Item = String> + 'a
where
I: Iterator<Item = String> + 'a,
{
// Some whatever filtering
lines.filter(move |line| line.starts_with(&query))
}
fn whatever<'a, I>(lines: I, query: &'a str) -> impl Iterator<Item = String> + 'a
where
I: Iterator<Item = String> + 'a,
{
// Some whatever operation
let mut sorted: Vec<String> = lines.collect();
sorted.sort_unstable();
sorted.into_iter().map(|s| s.to_lowercase())
}
I would like to be able to use one or the other and apply them on an iterator of String
One possibility is to use an enum
like so (playground):
pub enum Operator {
BeginsWith,
Whatever,
}
fn operate<'a, I>(operator: Operator, lines: I, query: &'a str) -> impl Iterator<Item = String> + 'a
where
I: Iterator<Item = String> + 'a,
{
match operator {
Operator::BeginsWith => begins_with(lines, query),
Operator::Whatever => whatever(lines, query),
}
}
But I get the following error (which is fair)
error[E0308]: match arms have incompatible types
--> src/lib.rs:30:31
|
28 | / match operator {
29 | | Operator::BeginsWith => begins_with(lines, query),
| | ------------------------- this is found to be of type `impl std::iter::Iterator`
30 | | Operator::Whatever => whatever(lines, query),
| | ^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
31 | | }
| |_____- `match` arms have incompatible types
|
= note: expected type `impl std::iter::Iterator` (opaque type)
found type `impl std::iter::Iterator` (opaque type)
Another approach would be to make a trait and have implementations of it (playground):
pub trait Operator {
pub fn operate<'a, I>(lines: I, query: &'a str) -> impl Iterator<Item = String> + 'a
where
I: Iterator<Item = String> + 'a;
}
But this is not allowed in Rust.
What mechanisms does Rust provide for me to return an Iterator
that depends on the arguments passed into the method implemented from a trait?