Reputation: 8577
I want to write a function that takes one iterator as input, and return an iterator with the same items but mutated. Like in this example:
fn greet(name: &mut String) {
name.insert_str(0, "Hello ");
}
fn to_greetings(names: impl Iterator<Item = String>) -> impl Iterator<Item = String> {
names.inspect(|name| greet(name))
}
This does not compile, since name
isn't mutable. I have tried adding mut
in various places without really understanding what I am doing, but without any success. How do I fix the above code?
I guess I need to make the items mutable, but apparently Item = mut String
is a syntax error.
Upvotes: 2
Views: 407
Reputation: 602115
If the item type of an iterator is String
, the iterator yields owned strings. The iterator transfers ownership of these strings to the consumer. The consumer can modify the strings, since it owns them.
However, you can't use inspect()
to modify the elements of an iterator. The closure passed to inspect()
receives an immutable reference to the items of the iterator, which can't be used to modify the items. The correct iterator adapter to modify items is map()
, so this works (but it doesn't feel particularly idiomatic to me):
fn to_greetings<I>(names: I) -> impl Iterator<Item = String>
where
I: Iterator<Item = String>,
{
names.map(|mut name| { greet(&mut name); name })
}
If you want to actually modify the strings in some underlying container, e.g. a vector of strings, you need a different approach though. A mutable iterator over a container of strings has an item type of &mut String
, so you'd need to use something like
fn to_greetings<'a, I>(names: I) -> impl Iterator<Item = &'a mut String>
where
I: Iterator<Item = &'a mut String>,
{
names.map(|name| { greet(name); name })
}
Upvotes: 3