Reputation: 6299
I'm trying to create a trait that extends iterator from strings and return a flat map, here is what I got so far
trait WordsExt<'a, F>: Iterator<Item = &'a str>
where
Self: Sized,
F: FnMut(&'a str) -> Split<'a, &'a str>,
{
fn words(self) -> FlatMap<Self, Split<'a, &'a str>, F> {
self.flat_map(|x: &'a str| x.split(" "))
}
}
I'm stuck on closure type.
I tried this too
struct Words<'a, I>
where
I: Iterator<Item = &'a str>,
{
inner: I,
}
trait WordsExt<'a>: Iterator<Item = &'a str>
where
Self: Sized,
{
fn words(
self,
) -> Words<'a, FlatMap<Self, Split<'a, &'a str>, Fn(Self::Item) -> Split<'a, &'a str>>>
{
Words {
inner: self.flat_map(|x: &'a str| x.split(" ")),
}
}
}
I just came across this problem every time. I need to return a trait. When I'm in a function I can use impl Trait
syntax. But when expressing a trait I can't express this. From what I could grasp, the closer I can get is to use generics, so that the method is monomorphized at call. But then I need to enable user to select the concrete type. In this case the closure is implementation detail, it should not leak to user.
I came across this answer How can I add new methods to Iterator?
In this case the OP use case has an inner state. In my case I just want to create an alias i.words() -> i.flat_map(|x| x.split(" "))
I know about coherence, so that I may need to create a wrapper over Iterator because Iterator is not under my crate. This was the second attempt.
I could implement a function by the way it was straightforward
fn words<'a>(i: impl Iterator<Item = &'a str>) -> impl Iterator<Item = &'a str> {
i.flat_map(|x| x.split(" "))
}
But I can't express the same with trait syntax because there is no impl Trait
syntax in traits. So ... I have two options, dynamic dispatch and generics, none of them are ideal. Going even further. Since these struct is unsized I can't use static dispatch on it, so I'm stuck on dynamic dispatch on something that would be simply simple
Invalid struct bellow
struct Words<'a>(Iterator<Item = &'a str>);
Finally, I expected that given a function F(X)
I would be able to always refactor it to write a X.F()
, but this seems not to be true because while I'm able to write fn f(x) -> impl Y
I'm not able to express trait X { fn (self) -> impl Y }
, at last not recurring to generics or dynamic dispatch.
I was trying to write iterator combinators in a kind of fluent syntax: iterator.comb1().comb2().comb3()
Upvotes: 2
Views: 390
Reputation: 4542
I got your code to compile by changing it as follows:
trait WordsExt<'a>: Iterator<Item = &'a str>
where
Self: Sized,
{
fn words(self) -> FlatMap<Self, Split<'a, &'a str>, fn(&'a str) -> Split<'a, &'a str>> {
self.flat_map(|x: &'a str| x.split(" "))
}
}
The trick is to replace the function trait object by the actual function type.
Upvotes: 2