In the Rust documentation for std::io::Read::read() I came across this example:
fn main() -> io::Result<()> {
let mut f = File::open("foo.txt")?;
let mut buffer = [0; 10];
// read up to 10 bytes
let n = f.read(&mut buffer[..])?;
// Is there any difference between the previous line and the next one?
// let n = f.read(&mut buffer)?;
println!("The bytes: {:?}", &buffer[..n]);
Ok(())
}
You can see let n = f.read(&mut buffer[..])?;
, buffer[ .. ]
contains all values from start to end and then we have a mutable reference to them.
Would it make any difference if I would write let n = f.read(&mut buffer)?;
instead?
I tried it and to me it seems the same, but I wondered why authors used &mut buffer[..]
, am I missing something?
The types are different:
buffer |
[u8; 10] |
&mut buffer |
&mut [u8; 10] |
&mut buffer[..] |
&mut [u8] |
buffer.as_mut_slice() |
&mut [u8] |
So why can a function that wants a &mut [u8]
argument take a &mut buffer
?
The magic here is in automatic type coercion, which states that a &mut [u8; 10]
can be coerced into a &mut [u8]
automatically.
Functionally, there is no difference. It's like the difference between an explicit and implicit cast. &mut [..]
converts to a slice explicitly and no coercion happens, &mut
does not convert explicitly and an implicit coercion happens. The resulting machine code will be identical.
For more information about the difference between [u8; 10]
and [u8]
, read What is the difference between a slice and an array?.
So writing f.read(&mut buffer)
is perfectly fine and, in my opinion, preferred to f.read(&mut buffer[..])
. It's just easier to read.
EDIT: @ChayimFriedman pointed out that coercion does not always happen automatically, which is correct. Coercion can only happen at coercion sites. The relevant coercion site for this example is using a variable as the 'argument for a function call'. If you have a situation where no coercion site is present, then the explicit conversion might indeed be required.