Iterator of char into String?


#1

Sorry for another basic sounding question.

I have a code fragment that produces an iterator of char.

How do I turn this into a string?


#2

You can call .collect() on the iterator, because of this impl:

impl FromIterator<char> for String { ... }

#3

Interesting. So my thought process should have been:

  1. Does String impl FromIterator ?
  2. Yes. Therefore, I can just collect() the iterator

?

That makes sense. Thanks!


#4

Right. I’ve never even used this impl, but my first thought upon seeing the question "I have an Iterator of X and need a Y" was to look at the FromIterator impls of Y.

If that impl didn’t exist, I’d then look for the following:

  • Other FromIterator<X> impls for String to see if any of those X can easily be produced from char (and then I would call map before .collect()).
  • impl FromIterator<char> for Vec<u8>. If this existed I would use String::from_utf8(iterator.collect()).
  • impl Add<char> for String. If this existed, I would use .fold(String::new(), |s, c| s + c)
  • methods of char to see if there’s anything that lets you obtain the UTF8 bytes. Indeed, there is encode_utf8, which even gives a &mut str, so one can write
    .fold(String::new(), |s, c| {
        let mut buffer = [u8; 4];
        s += &*c.encode_utf8(&mut buffer);
        s
    })
    
  • idly check the inherent methods of String for whatever pops out at me

and if I could still find nothing after all of that I’d slam my head into a wall somewhere.


TWiR quote of the week
#5

Got it, to get from Iterator<X> to Y we are searching for a path of the form:

1. X -> A,
2. collect: Iterator<A> -> B
3. B -> Y

step 2 is “impl FromIterator”; paths 1 & 3 is just taking reasonable guesses.


#6

Another one to check is Extend. Most collections implement Extend for the same item types as they do FromIterator, but they also tend to have implementations for references when the item implements Copy. For instance, Vec<T> implements FromIterator<T>, Extend<T>, and Extend<&'a T> where T: 'a + Copy.

FWIW, I think the reason Vec<T> doesn’t also implement a similar FromIterator<&T> is that it makes type inference harder. People often use a shorthands like let v: Vec<_> = iter.collect(); or iter.collect::<Vec<_>>(), but these would be ambiguous for collecting either Vec<T> or Vec<&T>.