Strange behaviour when pass &mut Vec<u8> to Read::read()

I tried:

 pub fn get(&self) -> io::Result<String> {
        let rd = &mut self.file.borrow_mut().read;
        rd.rewind()?;
        let mut data = Vec::new();
        rd.read(&mut data)?;
        dbg!(&data);
        let data = String::from_utf8_lossy(&data).into_owned();
        dbg!(&data);
        Ok(data)
    }

but Read::read() didn't add anything to the vector

Read::read accepts &mut [u8], not &mut Vec<u8>. To read to end, use Read::read_to_end instead which accepts &mut Vec<u8>. Also, because you are reading to string, you may also consider using Read::read_to_string.

Clippy will notice this problem: Clippy Lints.

1 Like

but doesen't the compiler do the conversion?

Vec<u8> has an implementation of DerefMut which can be used to deref coerce &mut Vec<u8> into &mut [u8].

In this case because the vector is empty you end up with essentially passing &mut [] to read function which tells read to not actually read anything.

I don't understand, shoulden't read() add bytes to the vector?

&mut [u8] cannot be resized, so it cannot grow to hold the additional data.

read_to_end and read_to_string specifically take &mut Vec<u8>, allowing them to resize (and potentially reallocate) when the buffer is filled.

2 Likes

Thank you!

1 Like

Beware that .read() returns a Result that you should check. On success the result contains the number of bytes read. Which may be less than the size of the given buffer.

3 Likes