Iterator of slice return reference or value?

why iterate it1 is return an value, but it2 is return an reference ?

let s1 = String::from("hello");

let it1 = s1.chars();

let it2 = s1.as_bytes().iter();

when i veiw the source code of chars() method:

pub fn chars(&self) -> Chars<'_> {
        Chars { iter: self.as_bytes().iter() }

pub struct Chars<'a> {
    pub(super) iter: slice::Iter<'a, u8>,

Is as_bytes().iter() return iterator yield u8 but not &u8 inside chars() method ?

Because it does different work in order to find the next Unicode code point (encoded as UTF8 bytes) and then translate to a char (encoded as an integer value).

Or rephrased, a String isn't a collection of chars, so Chars<'_> can't return a reference to some pre-existing chars in the String -- they don't exist. It decodes the UTF8 bytes to chars which it returns by value instead.

1 Like

Maybe a simpler example is in order. If you look at Copied<I>, it holds an I. So a Copied<Iter<'_, u8>> holds an Iter<'_, u8>, just like a Chars<'_> does.

But Copied<I> turns an iterator over &T to an iterator over T. It does this in the implementation (which requires T to implement Copy) by calling Option::copied, which in turn does a little work to copy out the T from the &T.

So Copied<Iter<'_, u8>> returns owned u8s. Example.

In general the point of iterators that wrap other iterators (call them combinators or what you will) is to change the behavior of the iterator, be that changing which items are returned, what type is returned, or both.

thanks for quick response, now i know why iterate Chars<'_> is return an char value. Can you tell me why self.as_bytes().iter() can passed to construct struct Chars instance ? since i think self.as_bytes().iter() is equal to s1.as_bytes().iter() return an Iter<&[u8]>

If you go to the documentation and then click "source" you can see that the chars method just constructs a Chars<'_> instances by calling self.as_bytes().iter().

They're not the same type because the Iter<'_, u8> is wrapped in a Chars<'_> when you call self.chars().

Just like you can put a String or Vec<u8> or whatever in a field of your own type, Chars<'_> has a Iter<'_, u8> in a field. There's nothing special or magical going on, it's just composition.