I'm looking for a type I could use to effectively express "thing that can be iterated on yielding &str
s", but without generics so my method is object-safe/dynamically dispatchable, and so it can be iterated on multiple times, i.e. some type of &dyn Iterable<str>
.
For example, what type could I put on strings
to make this code compile?
trait Foo {
fn process_strings(&self, strings: ???);
}
struct FooImpl;
impl Foo for FooImpl {
fn process_strings(&self, strings: ???) {
for s in strings {
println!("{}", s);
}
for s in strings {
println!("{}", s);
}
}
}
fn run_foo(foo: &dyn Foo) {
let a: Box<[&str]> = Box::from(["a", "b"]);
let b: Vec<&str> = a.to_vec();
let c: Vec<Arc<str>> = a.iter().copied().map(From::from).collect();
let d: Vec<String> = a.iter().copied().map(From::from).collect();
let e: HashSet<String> = a.iter().copied().map(From::from).collect();
foo.process_strings(&a);
foo.process_strings(&b);
foo.process_strings(&c);
foo.process_strings(&d);
foo.process_strings(&e);
}
fn main() {
run_foo(&FooImpl {});
}
I did manage to define a trait, but I'm just wondering if there's an easier way to do this with the standard library or a common crate?
This is what I came up with so I can write &dyn Iterable<str>
. Playground link.
trait Iterable<'a, T: ?Sized>
where
Self: 'a,
{
fn boxed_iter(&'a self) -> Box<dyn Iterator<Item = &'a T> + 'a>;
}
impl<'a, I: 'a + ?Sized, T: Borrow<O> + 'a + ?Sized, O: ?Sized> Iterable<'a, O> for I
where
&'a I: IntoIterator<Item = &'a T>,
{
fn boxed_iter(&'a self) -> Box<dyn Iterator<Item = &'a O> + 'a> {
Box::new(self.into_iter().map(Borrow::borrow))
}
}
impl<'a, T: ?Sized> IntoIterator for &dyn Iterable<'a, T>
where
Self: 'a,
{
type Item = &'a T;
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
fn into_iter(self) -> Self::IntoIter {
self.boxed_iter()
}
}
Thanks!